oldap-tools 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.1
2
+ Name: oldap-tools
3
+ Version: 0.1.0
4
+ Summary: CLI tools for OLDAP
5
+ License: GPL-3.0-only
6
+ Author: Lukas Rosenthaler
7
+ Author-email: lukas.rosenthaler@unibas.ch
8
+ Requires-Python: >=3.13,<4.0
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Dist: oldaplib (>=0.3.28,<0.4.0)
12
+ Requires-Dist: rdflib (>=7.5.0,<8.0.0)
13
+ Requires-Dist: typer (>=0.20.0,<0.21.0)
14
+ Description-Content-Type: text/markdown
15
+
16
+ [![PyPI version](https://badge.fury.io/py/oldap-tools.svg)](https://badge.fury.io/py/oldap-tools)
17
+ [![GitHub release](https://img.shields.io/github/v/release/OMAS-IIIF/oldap-tools)](https://github.com/OMAS-IIIF/oldap-tools/releases)
18
+ # OLADP tools
19
+
20
+ OLDAP tools is a CLI tool for managing parts of the OLDAP framework. It allows to
21
+
22
+ - dump all the data of a given project to a gzipped TriG file
23
+ - load a project from a gzipped TriG file created by oldap-tools
24
+ - load a hierarchical list from a YAML file
25
+ - dump a hierarchical list to a YAML file
26
+
27
+ # Installation
28
+
29
+ The installation is done using pip: `pip install oldap-tools`
30
+
31
+ # Usage
32
+
33
+ The CLI tool provides the following commands:
34
+
35
+ - `oldap-tools project dump`: Dump all the data of a given project to a gzipped TriG file
36
+ - `oldap-tools project load`: Load a project from a gzipped TriG file created by oldap-tools
37
+ - `oldap-tools list dump`: Dump a hierarchical list to a YAML file
38
+ - `oldap-tools list load`: Load a hierarchical list from a YAML file
39
+
40
+ # Common options
41
+
42
+ - `--graphdb`, `-g`: URL of the GraphDB server (default: "http://localhost:7200")
43
+ - `--repo`, `-r`: Name of the repository (default: "oldap")
44
+ - `--user`, `-u`: OLDAP user (*required*) which performs the operations
45
+ - `--password` `-p`: OLDAP password (*required*)
46
+ - `--graphdb_user`: GraphDB user (default: None). Not needed if GraphDB runs without athentification.
47
+ - `--graphdb_password`: GraphDB password (default: None). Not needed if GraphDB runs without athentification.
48
+ - `--verbose`, `-v`: Print more information
49
+
50
+ # Command
51
+
52
+ ## Project dump
53
+
54
+ This command dumps all the data of a given project to a gzipped TriG file. It includes user information
55
+ of all users associated with the project. The command has the following syntax (in addition to the common options):
56
+
57
+ ```oldap-tools [common_options] [graphdb-options] project dump [-out <filename>] [--data | --no-data] [-verbose] <project_id>```
58
+
59
+ The graphdb options see above. The other options are defined as follows:
60
+
61
+ - `-out <filename>`: Name of the output file (default: "<project_id>.trig.gz")
62
+ - `--data | --no-data`: Include or exclude the data of the project (default: include)
63
+ - `-verbose`: Print more information
64
+ - `<project_id>`: Project identifier (project shortname)
65
+
66
+ The file is basically a dump of the project specific named graphs of the GraphDB repository.
67
+ This are the following graphs:
68
+
69
+ - `<project_id>:shacl`: Contains all the SHACL shapes of the project
70
+ - `<project_id>:onto`: Contains all the OWL ontology information of the project
71
+ - `<project_id>:lists`: Contains all the hierarchical lists of the project
72
+ - `<project_id>:data`: Contains all the resources (instances) of the project
73
+
74
+ The user information is stored as special comment in the TriG file and is interpreted by oldap-tools project load.
75
+
76
+ ## Project load
77
+
78
+ This command loads a project from a gzipped TriG file created by oldap-tools. It has the following syntax
79
+ (in addition to the common options):
80
+
81
+ ```oldap-tools [common_options] [graphdb-options] project load --i <filename>```
82
+
83
+ The options are as follows:
84
+
85
+ - `--inf`, `-i`: Name of the input file (required)
86
+ - `-verbose`: Print more information
87
+
88
+ If a user does not exist, then the user is created. If the User is already existing, then the user is replaced.
89
+
90
+ *NOTE: This will change in the future in order to only update project specific permissions to the existing user.*
91
+
92
+ ## List dump
93
+
94
+ This command dumps a hierarchical list to a YAML file. This file can be edited to add/remove or change list items.
95
+ The command has the following syntax (in addition to the common options):
96
+
97
+ ```oldap-tools [common_options] list dump [-out <filename>] <project_id> <list_id>```
98
+
99
+ This command generates a YAML file which can be edited and contains the list and all it nodes
100
+
101
+ The options are as follows:
102
+
103
+ - `-out `, `-o`: Output file
104
+ - `<project_id>`: Project identifier (project shortname)
105
+ - `<list_id>`: List identifier
106
+
107
+ ## List load
108
+
109
+ This command loads a hierarchical list from a YAML file into the given project. The command has the following syntax
110
+ (in addition to the common options):
111
+
112
+ ```oldap-tools [common_options] list load --inf <filename> <project_id>```
113
+
114
+ The options are as follows:
115
+
116
+ - `--inf`, `-i`: Name of the input file (required)
117
+ - `<project_id>`: Project identifier (project shortname)
118
+
119
+
120
+
@@ -0,0 +1,104 @@
1
+ [![PyPI version](https://badge.fury.io/py/oldap-tools.svg)](https://badge.fury.io/py/oldap-tools)
2
+ [![GitHub release](https://img.shields.io/github/v/release/OMAS-IIIF/oldap-tools)](https://github.com/OMAS-IIIF/oldap-tools/releases)
3
+ # OLADP tools
4
+
5
+ OLDAP tools is a CLI tool for managing parts of the OLDAP framework. It allows to
6
+
7
+ - dump all the data of a given project to a gzipped TriG file
8
+ - load a project from a gzipped TriG file created by oldap-tools
9
+ - load a hierarchical list from a YAML file
10
+ - dump a hierarchical list to a YAML file
11
+
12
+ # Installation
13
+
14
+ The installation is done using pip: `pip install oldap-tools`
15
+
16
+ # Usage
17
+
18
+ The CLI tool provides the following commands:
19
+
20
+ - `oldap-tools project dump`: Dump all the data of a given project to a gzipped TriG file
21
+ - `oldap-tools project load`: Load a project from a gzipped TriG file created by oldap-tools
22
+ - `oldap-tools list dump`: Dump a hierarchical list to a YAML file
23
+ - `oldap-tools list load`: Load a hierarchical list from a YAML file
24
+
25
+ # Common options
26
+
27
+ - `--graphdb`, `-g`: URL of the GraphDB server (default: "http://localhost:7200")
28
+ - `--repo`, `-r`: Name of the repository (default: "oldap")
29
+ - `--user`, `-u`: OLDAP user (*required*) which performs the operations
30
+ - `--password` `-p`: OLDAP password (*required*)
31
+ - `--graphdb_user`: GraphDB user (default: None). Not needed if GraphDB runs without athentification.
32
+ - `--graphdb_password`: GraphDB password (default: None). Not needed if GraphDB runs without athentification.
33
+ - `--verbose`, `-v`: Print more information
34
+
35
+ # Command
36
+
37
+ ## Project dump
38
+
39
+ This command dumps all the data of a given project to a gzipped TriG file. It includes user information
40
+ of all users associated with the project. The command has the following syntax (in addition to the common options):
41
+
42
+ ```oldap-tools [common_options] [graphdb-options] project dump [-out <filename>] [--data | --no-data] [-verbose] <project_id>```
43
+
44
+ The graphdb options see above. The other options are defined as follows:
45
+
46
+ - `-out <filename>`: Name of the output file (default: "<project_id>.trig.gz")
47
+ - `--data | --no-data`: Include or exclude the data of the project (default: include)
48
+ - `-verbose`: Print more information
49
+ - `<project_id>`: Project identifier (project shortname)
50
+
51
+ The file is basically a dump of the project specific named graphs of the GraphDB repository.
52
+ This are the following graphs:
53
+
54
+ - `<project_id>:shacl`: Contains all the SHACL shapes of the project
55
+ - `<project_id>:onto`: Contains all the OWL ontology information of the project
56
+ - `<project_id>:lists`: Contains all the hierarchical lists of the project
57
+ - `<project_id>:data`: Contains all the resources (instances) of the project
58
+
59
+ The user information is stored as special comment in the TriG file and is interpreted by oldap-tools project load.
60
+
61
+ ## Project load
62
+
63
+ This command loads a project from a gzipped TriG file created by oldap-tools. It has the following syntax
64
+ (in addition to the common options):
65
+
66
+ ```oldap-tools [common_options] [graphdb-options] project load --i <filename>```
67
+
68
+ The options are as follows:
69
+
70
+ - `--inf`, `-i`: Name of the input file (required)
71
+ - `-verbose`: Print more information
72
+
73
+ If a user does not exist, then the user is created. If the User is already existing, then the user is replaced.
74
+
75
+ *NOTE: This will change in the future in order to only update project specific permissions to the existing user.*
76
+
77
+ ## List dump
78
+
79
+ This command dumps a hierarchical list to a YAML file. This file can be edited to add/remove or change list items.
80
+ The command has the following syntax (in addition to the common options):
81
+
82
+ ```oldap-tools [common_options] list dump [-out <filename>] <project_id> <list_id>```
83
+
84
+ This command generates a YAML file which can be edited and contains the list and all it nodes
85
+
86
+ The options are as follows:
87
+
88
+ - `-out `, `-o`: Output file
89
+ - `<project_id>`: Project identifier (project shortname)
90
+ - `<list_id>`: List identifier
91
+
92
+ ## List load
93
+
94
+ This command loads a hierarchical list from a YAML file into the given project. The command has the following syntax
95
+ (in addition to the common options):
96
+
97
+ ```oldap-tools [common_options] list load --inf <filename> <project_id>```
98
+
99
+ The options are as follows:
100
+
101
+ - `--inf`, `-i`: Name of the input file (required)
102
+ - `<project_id>`: Project identifier (project shortname)
103
+
104
+
@@ -0,0 +1,22 @@
1
+ [tool.poetry]
2
+ name = "oldap-tools"
3
+ version = "0.1.0"
4
+ description = "CLI tools for OLDAP"
5
+ authors = ["Lukas Rosenthaler <lukas.rosenthaler@unibas.ch>"]
6
+ readme = "README.md"
7
+ license = "GPL-3.0-only"
8
+ packages = [{ include = "oldap_tools", from = "src" }]
9
+
10
+
11
+ [tool.poetry.dependencies]
12
+ python = "^3.13"
13
+ oldaplib = "^0.3.28"
14
+ typer = "^0.20.0"
15
+ rdflib = "^7.5.0"
16
+
17
+ [tool.poetry.scripts]
18
+ oldap-tools = "oldap_tools.cli:main"
19
+
20
+ [build-system]
21
+ requires = ["poetry-core"]
22
+ build-backend = "poetry.core.masonry.api"
File without changes
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,115 @@
1
+ import enum
2
+ from pathlib import Path
3
+
4
+ import typer
5
+ from importlib.metadata import version
6
+
7
+ from dump_list import dump_list
8
+ from oldap_tools.config import AppConfig
9
+ from oldap_tools.dump_project import dump_project
10
+ from oldap_tools.load_list import load_list
11
+ from oldap_tools.load_project import load_project
12
+
13
+ from oldap_tools.logging import setup_logging
14
+
15
+ app = typer.Typer(
16
+ no_args_is_help=True,
17
+ help="OLDAP command line tools"
18
+ )
19
+
20
+ @app.callback()
21
+ def app_callback(ctx: typer.Context,
22
+ verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose (debug) logging"),
23
+ graphdb_base: str = typer.Option("http://localhost:7200", "--graphdb", "-g", help="GraphDB base URL"),
24
+ repo: str = typer.Option("oldap", "--repo", "-r", help="GraphDB repository"),
25
+ user: str = typer.Option(..., "--user", "-u", help="OLDAP user"),
26
+ password: str = typer.Option(..., "--password", "-p", help="OLDAP password", hide_input=True),
27
+ graphdb_user: str = typer.Option(None, "--graphdb_user", envvar="GRAPHDB_USER", help="GraphDB user"),
28
+ graphdb_password: str = typer.Option(None, "--graphdb_password", envvar="GRAPHDB_PASSWORD", help="GraphDB password", hide_input=True)
29
+ ):
30
+ setup_logging(verbose)
31
+ ctx.obj = AppConfig(
32
+ graphdb_base=graphdb_base,
33
+ repo=repo,
34
+ user=user,
35
+ password=password,
36
+ graphdb_user=graphdb_user,
37
+ graphdb_password=graphdb_password
38
+ )
39
+
40
+ @app.command()
41
+ def show_version():
42
+ """Show version information."""
43
+ typer.echo(version("oldap-tools"))
44
+
45
+ project = typer.Typer(help="Project-related commands")
46
+ app.add_typer(project, name="project")
47
+
48
+ @project.command("dump")
49
+ def project_dump(
50
+ ctx: typer.Context,
51
+ project_id: str = typer.Argument(..., help="Project ID (e.g. swissbritnet, hyha, ...)"),
52
+ out: Path = typer.Option(Path("<project>.trig.gz"), "--out", "-o", help="Output dump file"),
53
+ include_data: bool = typer.Option(True, "--data/--no-data", help="Include '<project>:data' graph"),
54
+ ):
55
+ """Export project data."""
56
+ if out == Path("<project>.trig.gz"):
57
+ out = Path(project_id).with_suffix(".trig.gz")
58
+ typer.echo(f"Exporting '{project_id}' data to {out}")
59
+ cfg = ctx.obj
60
+ dump_project(project_id=project_id,
61
+ graphdb_base=cfg.graphdb_base,
62
+ repo=cfg.repo,
63
+ out=out,
64
+ include_data=include_data,
65
+ user=cfg.user,
66
+ password=cfg.password,
67
+ graphdb_user=cfg.graphdb_user,
68
+ graphdb_password=cfg.graphdb_password)
69
+
70
+ @project.command("load")
71
+ def project_load(ctx: typer.Context,
72
+ inf: Path = typer.Option(Path("dump.trig.gz"), "--inf", "-i", help="Input file for load")):
73
+ cfg = ctx.obj
74
+ load_project(graphdb_base=cfg.graphdb_base,
75
+ repo=cfg.repo,
76
+ inf=inf,
77
+ user=cfg.user,
78
+ password=cfg.password,
79
+ graphdb_user=cfg.graphdb_user,
80
+ graphdb_password=cfg.graphdb_password)
81
+
82
+ lists = typer.Typer(help="List-related commands")
83
+ app.add_typer(lists, name="lists")
84
+
85
+ @lists.command("dump", help="Dump all list data to a YAML file.")
86
+ def list_dump(ctx: typer.Context,
87
+ project_id: str = typer.Argument(..., help="Project ID (e.g. swissbritnet, hyha, ...)"),
88
+ list_id: str = typer.Argument(..., help="List ID (e.g. 'CreativeCommons', 'BuildingCategories', ...)"),
89
+ out: Path = typer.Option(Path("dump.trig"), "--out", "-o", help="Output dump file")):
90
+ cfg = ctx.obj
91
+ dump_list(project_id=project_id,
92
+ list_id=list_id,
93
+ graphdb_base=cfg.graphdb_base,
94
+ repo=cfg.repo,
95
+ filepath=out,
96
+ user=cfg.user,
97
+ password=cfg.password,
98
+ graphdb_user = cfg.graphdb_user,
99
+ graphdb_password = cfg.graphdb_password
100
+ )
101
+
102
+ @lists.command("load", help="Load project data from a JSON/YAML file.")
103
+ def list_load(ctx: typer.Context,
104
+ project_id: str = typer.Argument(..., help="Project ID (e.g. swissbritnet, hyha, ...)"),
105
+ inf: Path = typer.Option(Path("dump.trig.gz"), "--inf", "-i", help="Input file for load")):
106
+ cfg = ctx.obj
107
+ load_list(project_id=project_id,
108
+ graphdb_base=cfg.graphdb_base,
109
+ repo=cfg.repo,
110
+ filepath=inf,
111
+ user=cfg.user,
112
+ password=cfg.password)
113
+
114
+ def main():
115
+ app()
@@ -0,0 +1,11 @@
1
+ # src/oldap_tools/config.py
2
+ from dataclasses import dataclass
3
+
4
+ @dataclass(frozen=True)
5
+ class AppConfig:
6
+ graphdb_base: str
7
+ repo: str
8
+ user: str | None = None
9
+ password: str | None = None
10
+ graphdb_user: str | None = None
11
+ graphdb_password: str | None = None
@@ -0,0 +1,127 @@
1
+ import gzip
2
+ import json
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+
6
+ import requests
7
+ import typer
8
+ import logging
9
+
10
+ from oldaplib.src.connection import Connection
11
+ from oldaplib.src.helpers.context import Context
12
+ from oldaplib.src.helpers.oldaperror import OldapError
13
+ from oldaplib.src.helpers.serializer import serializer
14
+ from oldaplib.src.permissionset import PermissionSet
15
+ from oldaplib.src.project import Project
16
+ from oldaplib.src.user import User
17
+ from oldaplib.src.xsd.xsd_qname import Xsd_QName
18
+ from rdflib import Dataset
19
+
20
+ log = logging.getLogger(__name__)
21
+
22
+ def export_graphs_as_trig(
23
+ graphdb_base: str, # e.g. "http://localhost:7200"
24
+ repo: str, # e.g. "oldap"
25
+ graph_iris: list[str], # the 4 graphs you want
26
+ auth: tuple[str, str] | None = None,
27
+ timeout: int = 120,
28
+ ) -> str:
29
+ ds = Dataset()
30
+
31
+ for g in graph_iris:
32
+ # RDF4J "statements" endpoint; context must be given as <IRI>
33
+ url = f"{graphdb_base.rstrip('/')}/repositories/{repo}/statements"
34
+ params = {"context": f"<{g}>"}
35
+ r = requests.get(
36
+ url,
37
+ params=params,
38
+ headers={"Accept": "application/n-quads"},
39
+ auth=auth,
40
+ timeout=timeout,
41
+ )
42
+ if r.status_code != 200:
43
+ log.error(f"ERROR: Request to '{url}' failed with status code {r.status_code}")
44
+ raise typer.Exit(code=1)
45
+
46
+ # N-Quads keeps the graph/context in each statement -> perfect for Dataset
47
+ ds.parse(data=r.text, format="nquads")
48
+
49
+ trig = ds.serialize(format="trig")
50
+ return trig.decode("utf-8") if isinstance(trig, bytes) else trig
51
+
52
+
53
+ def dump_project(project_id: str,
54
+ graphdb_base: str,
55
+ repo: str,
56
+ out: Path,
57
+ include_data: bool,
58
+ user: str,
59
+ password: str,
60
+ graphdb_user: str | None = None,
61
+ graphdb_password: str | None = None):
62
+ try:
63
+ con = Connection(server=graphdb_base,
64
+ repo = repo,
65
+ dbuser=graphdb_user,
66
+ dbpassword=graphdb_password,
67
+ userId=user,
68
+ credentials=password)
69
+ except OldapError as e:
70
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {e}")
71
+ raise typer.Exit(code=1)
72
+
73
+ try:
74
+ project = Project.read(con=con, projectIri_SName=project_id)
75
+ except OldapError as e:
76
+ log.error(f"ERROR: Failed to connect to read project '{project_id}': {e}")
77
+ raise typer.Exit(code=1)
78
+
79
+ trig = "################################################################################\n"
80
+ trig += f"# Project: {project.projectShortName}\n"
81
+ trig += f"# Date: {datetime.now().isoformat()}\n"
82
+ trig += "################################################################################\n"
83
+ trig += "\n#\n# User info\n#\n"
84
+ userIris = User.search(con=con, inProject=project.projectIri)
85
+ for userIri in userIris:
86
+ user = User.read(con=con, userId=str(userIri))
87
+ user_json = json.dumps(user, default=serializer.encoder_default)
88
+ trig += "#>> " + user_json + "\n"
89
+ trig += "#<<\n\n"
90
+
91
+ context = Context(name=con.context_name)
92
+ trig += context.turtle_context
93
+ trig += "#\n# Load the oldap:admin part\n#\n"
94
+ trig += "oldap:admin {"
95
+
96
+ trig += "\n#\n# Project info\n#\n"
97
+ trig += project.trig_to_str(created=project.created, modified=project.modified, indent=1)
98
+ trig += " .\n\n"
99
+
100
+ trig += "\n#\n# PermissionSet info\n#\n"
101
+ permsetQNames = PermissionSet.search(con=con, definedByProject=project.projectIri)
102
+ for permsetQName in permsetQNames:
103
+ permset = PermissionSet.read(con=con, qname=permsetQName)
104
+ trig += permset.trig_to_str(created=permset.created, modified=permset.modified, indent=1)
105
+ trig += " .\n\n"
106
+
107
+ trig += "\n}\n\n"
108
+
109
+ project_graphs = [
110
+ str(context.qname2iri(Xsd_QName(project.projectShortName, "shacl"))),
111
+ str(context.qname2iri(Xsd_QName(project.projectShortName, "onto"))),
112
+ str(context.qname2iri(Xsd_QName(project.projectShortName, "lists"))),
113
+ ]
114
+ if include_data:
115
+ project_graphs.append(str(context.qname2iri(Xsd_QName(project.projectShortName, "data"))))
116
+
117
+ trig += export_graphs_as_trig(
118
+ graphdb_base="http://localhost:7200",
119
+ repo="oldap",
120
+ graph_iris=project_graphs,
121
+ auth=None, # or None
122
+ )
123
+
124
+ with gzip.open(out, "wt", encoding="utf-8", newline="") as f:
125
+ f.write(trig)
126
+
127
+
@@ -0,0 +1,39 @@
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ import typer
5
+ from oldaplib.src.connection import Connection
6
+ from oldaplib.src.helpers.oldaperror import OldapError
7
+ from oldaplib.src.oldaplist_helpers import load_list_from_yaml
8
+ from oldaplib.src.project import Project
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+ def load_list(project_id: str,
13
+ graphdb_base: str,
14
+ repo: str,
15
+ filepath: Path,
16
+ user: str,
17
+ password: str,
18
+ graphdb_user: str | None = None,
19
+ graphdb_password: str | None = None):
20
+
21
+ try:
22
+ connection = Connection(server=graphdb_base,
23
+ repo=repo,
24
+ dbuser=graphdb_user,
25
+ dbpassword=graphdb_password,
26
+ userId=user,
27
+ credentials=password,
28
+ context_name="DEFAULT")
29
+ project = Project.read(connection, project_id)
30
+ listnodes = load_list_from_yaml(con=connection,
31
+ project=project_id,
32
+ filepath=filepath)
33
+ except OldapError as error:
34
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {error}")
35
+ raise typer.Exit(code=1)
36
+ except FileNotFoundError as error:
37
+ log.error(f"ERROR: File {filepath} not found': {error}")
38
+ raise typer.Exit(code=1)
39
+
@@ -0,0 +1,107 @@
1
+ import gzip
2
+ import json
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import requests
7
+ import typer
8
+ from oldaplib.src.cachesingleton import CacheSingletonRedis
9
+ from oldaplib.src.connection import Connection
10
+ from oldaplib.src.helpers.oldaperror import OldapErrorAlreadyExists, OldapError, OldapErrorNotFound
11
+ from oldaplib.src.helpers.serializer import serializer
12
+ from oldaplib.src.user import User
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+ def import_trig(
17
+ graphdb_base: str,
18
+ repo: str,
19
+ trig_str: str,
20
+ auth: tuple[str, str] | None = None,
21
+ timeout: int = 120,
22
+ ):
23
+ url = f"{graphdb_base.rstrip('/')}/repositories/{repo}/statements"
24
+ r = requests.post(
25
+ url,
26
+ data=trig_str.encode("utf-8"),
27
+ headers={"Content-Type": "application/trig"},
28
+ auth=auth,
29
+ timeout=timeout,
30
+ )
31
+ if r.status_code != 200:
32
+ log.error(f"ERROR: Request to '{url}' failed with status code {r.status_code}")
33
+ raise typer.Exit(code=1)
34
+
35
+
36
+ def import_trig_gz(
37
+ graphdb_base: str,
38
+ repo: str,
39
+ trig_gz: bytes,
40
+ auth: tuple[str, str] | None = None,
41
+ timeout: int = 120,
42
+ ):
43
+ url = f"{graphdb_base.rstrip('/')}/repositories/{repo}/statements"
44
+ r = requests.post(
45
+ url,
46
+ data=trig_gz,
47
+ headers={
48
+ "Content-Type": "application/trig",
49
+ "Content-Encoding": "gzip",
50
+ },
51
+ auth=auth,
52
+ timeout=timeout,
53
+ )
54
+ if r.status_code < 200 or r.status_code >= 300:
55
+ log.error(f"ERROR: Request to '{url}' failed with status code {r.status_code}")
56
+ raise typer.Exit(code=1)
57
+
58
+
59
+ def load_project(graphdb_base: str,
60
+ repo: str,
61
+ inf: Path,
62
+ user: str,
63
+ password: str,
64
+ graphdb_user: str | None = None,
65
+ graphdb_password: str | None = None) -> None:
66
+ cache = CacheSingletonRedis()
67
+ cache.clear()
68
+
69
+ with open(inf, "rb") as f:
70
+ import_trig_gz(graphdb_base=graphdb_base,
71
+ repo=repo,
72
+ auth=(graphdb_user, graphdb_password) if graphdb_user and graphdb_password else None,
73
+ trig_gz=f.read())
74
+
75
+ try:
76
+ con = Connection(server=graphdb_base,
77
+ repo=repo,
78
+ dbuser=graphdb_user,
79
+ dbpassword=graphdb_password,
80
+ userId=user,
81
+ credentials=password)
82
+ except OldapError as e:
83
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {e}")
84
+ raise typer.Exit(code=1)
85
+
86
+ with gzip.open(inf, "rt", encoding="utf-8") as f:
87
+ for line in f:
88
+ if line.startswith('#>>'):
89
+ user_json = line[3:].strip()
90
+ user = json.loads(user_json, object_hook=serializer.make_decoder_hook(connection=con))
91
+ try:
92
+ existing_user = User.read(con=con, userId=user.userId)
93
+ except OldapErrorNotFound:
94
+ # user does not exist -> create it
95
+ user.create(keep_dates=True)
96
+ log.info(f"Created user {user.userId}")
97
+ else:
98
+ # user exists -> update it
99
+ if user.hasPermissions != existing_user.hasPermissions or user.inProject != existing_user.inProject:
100
+ existing_user.delete()
101
+ user.create(keep_dates=True)
102
+ log.info(f"Updated (replaced) user {user.userId}")
103
+ pass
104
+ if line.startswith('#<<'):
105
+ break
106
+
107
+
@@ -0,0 +1,13 @@
1
+ import logging
2
+ import sys
3
+
4
+ def setup_logging(verbose: bool = False) -> None:
5
+ level = logging.DEBUG if verbose else logging.INFO
6
+
7
+ logging.basicConfig(
8
+ level=level,
9
+ format="%(levelname)s: %(message)s",
10
+ handlers=[
11
+ logging.StreamHandler(sys.stderr)
12
+ ],
13
+ )