nl.export 1.4.0__py3-none-any.whl

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.
nl/export/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ # -*- coding: UTF-8 -*-
2
+ """Beschreibung
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2023 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
nl/export/config.py ADDED
@@ -0,0 +1,62 @@
1
+ # -*- coding: UTF-8 -*-
2
+ """Config
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2023 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ # Imports
12
+ import configparser
13
+ import logging
14
+ import os
15
+ import shutil
16
+ from enum import Enum
17
+ from pathlib import Path
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ _config_path = Path(os.environ["HOME"])
22
+
23
+ if "XDG_CONFIG_HOME" in os.environ:
24
+ _config_path = _config_path / os.environ["XDG_CONFIG_HOME"]
25
+ else:
26
+ _config_path = _config_path / ".config"
27
+ _config_path.mkdir(exist_ok=True)
28
+
29
+ NLCONFIG = _config_path / "nl_export.conf"
30
+ NLCONFIG_Deprecated = (
31
+ (Path(os.environ["HOME"]) / ".nl_export.conf"),
32
+ (_config_path / ".nl_export.conf"),
33
+ )
34
+
35
+ for cpath in NLCONFIG_Deprecated:
36
+ if cpath.is_file():
37
+ shutil.move(cpath, NLCONFIG)
38
+
39
+ NLACCESS_TOKEN = None
40
+ NLBASE_URL = None
41
+ NLUSER_AGENT = "nl-export-bot/1.0"
42
+
43
+ try:
44
+ config = configparser.ConfigParser()
45
+ config.read(NLCONFIG)
46
+
47
+ NLACCESS_TOKEN = config.get("plone", "access-token")
48
+ NLBASE_URL = config.get("plone", "base-url")
49
+ except Exception:
50
+ pass
51
+
52
+
53
+ class LicenceModels(Enum):
54
+ NLLicenceModelStandard = (
55
+ "Products.VDNL.content.NLLicenceModelStandard.INLLicenceModelStandard"
56
+ )
57
+ NLLicenceModelOptIn = (
58
+ "Products.VDNL.content.NLLicenceModelOptIn.INLLicenceModelOptIn"
59
+ )
60
+ # NLLicenceModelSingleUser = (
61
+ # "Products.VDNL.content.NLLicenceModelSingleUser.INLLicenceModelSingleUser"
62
+ # )
nl/export/errors.py ADDED
@@ -0,0 +1,23 @@
1
+ # -*- coding: UTF-8 -*-
2
+ """Errors
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2023 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ # Imports
12
+
13
+
14
+ class NoConfig(OSError):
15
+ pass
16
+
17
+
18
+ class NoMember(BaseException):
19
+ pass
20
+
21
+
22
+ class Unauthorized(BaseException):
23
+ pass
@@ -0,0 +1,9 @@
1
+ """Beschreibung
2
+
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2024 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
@@ -0,0 +1,138 @@
1
+ """Beschreibung
2
+
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2024 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ import csv
12
+ import typing
13
+ from argparse import Namespace
14
+ from contextlib import AbstractContextManager
15
+ from types import TracebackType
16
+
17
+ from nl.export.plone import LicenceModel
18
+ from nl.export.utils import get_unique_path, get_wf_state, option_title, secure_filename
19
+
20
+
21
+ class LFormatCSV(AbstractContextManager):
22
+ def __init__(self, lmodel: LicenceModel, options: Namespace) -> None:
23
+ self.lmodel = lmodel
24
+ self.options = options
25
+ self.destination = self.options.ablage.absolute()
26
+
27
+ self.cfh = None
28
+ self.csvpath = None
29
+ self.writer = None
30
+
31
+ def add_row(self, licence: dict | None, licencee: dict | None) -> dict:
32
+ match self.options.version:
33
+ case 2:
34
+ self.add_row_version_2(licence, licencee)
35
+ case _:
36
+ self.add_row_version_1(licence, licencee)
37
+
38
+ def add_row_version_1(self, licence: dict | None, licencee: dict | None) -> dict:
39
+ licencee = {} if licencee is None else licencee.plone_item
40
+
41
+ ipv4_allow = licencee.get("ipv4_allow", "")
42
+ ipv4_deny = None
43
+ ezb_id = licencee.get("ezb_id", "")
44
+
45
+ row = {}
46
+ row["user_name"] = licencee.get("uid", "")
47
+ row["status"] = get_wf_state(licencee)
48
+ row["title"] = licencee.get("title", "")
49
+ row["street"] = licencee.get("street", "")
50
+ row["zip"] = licencee.get("zip", "")
51
+ row["city"] = licencee.get("city", "")
52
+ row["county"] = option_title(licencee, "county")
53
+ row["country"] = option_title(licencee, "country")
54
+ row["telephone"] = licencee.get("telephone", "")
55
+ row["fax"] = licencee.get("fax", "")
56
+ row["email"] = licencee.get("email", "")
57
+ row["url"] = licencee.get("url", "")
58
+ row["contactperson"] = licencee.get("contactperson", "")
59
+ row["sigel"] = licencee.get("sigel", "")
60
+ row["ezb_id"] = ",".join(ezb_id) if isinstance(ezb_id, list) else ""
61
+ row["subscriber_group"] = option_title(licencee, "subscriper_group")
62
+ row["ipv4_allow"] = ",".join(ipv4_allow) if isinstance(ipv4_allow, list) else ""
63
+ row["ipv4_deny"] = ",".join(ipv4_deny) if isinstance(ipv4_deny, list) else ""
64
+ row["shib_provider_id"] = licencee.get("shib_provider_id", "")
65
+ row["zuid"] = licencee.get("UID", "")
66
+ row["mtime"] = licencee.get("modified", "")
67
+
68
+ if licence is None:
69
+ self.writer.writerow(row.keys())
70
+ else:
71
+ self.writer.writerow(row.values())
72
+
73
+ return row
74
+
75
+ def add_row_version_2(self, licence: dict | None, licencee: dict | None) -> dict:
76
+ licencee = {} if licencee is None else licencee.plone_item
77
+
78
+ ipv4_allow = licencee.get("ipv4_allow", "")
79
+ ipv6 = licencee.get("ipv6", "")
80
+ ezb_id = licencee.get("ezb_id", "")
81
+ foreign_keys = licencee.get("foreign_keys", "")
82
+
83
+ row = {}
84
+ row["user_name"] = licencee.get("uid", "")
85
+ row["status"] = get_wf_state(licencee)
86
+ row["title"] = licencee.get("title", "")
87
+ row["street"] = licencee.get("street", "")
88
+ row["zip"] = licencee.get("zip", "")
89
+ row["city"] = licencee.get("city", "")
90
+ row["county"] = option_title(licencee, "county")
91
+ row["country"] = option_title(licencee, "country")
92
+ row["telephone"] = licencee.get("telephone", "")
93
+ row["fax"] = licencee.get("fax", "")
94
+ row["email"] = licencee.get("email", "")
95
+ row["url"] = licencee.get("url", "")
96
+ row["contactperson"] = licencee.get("contactperson", "")
97
+ row["sigel"] = licencee.get("sigel", "")
98
+ row["ezb_id"] = ",".join(ezb_id) if isinstance(ezb_id, list) else ""
99
+ row["isni"] = licencee.get("isni", "")
100
+ row["foreign_keys"] = (
101
+ ",".join(foreign_keys) if isinstance(foreign_keys, list) else ""
102
+ )
103
+ row["subscriber_group"] = option_title(licencee, "subscriper_group")
104
+ row["ipv4_allow"] = ",".join(ipv4_allow) if isinstance(ipv4_allow, list) else ""
105
+ row["ipv6"] = ",".join(ipv6) if isinstance(ipv6, list) else ""
106
+ row["shib_provider_id"] = licencee.get("shib_provider_id", "")
107
+ row["zuid"] = licencee.get("UID", "")
108
+ row["mtime"] = licencee.get("modified", "")
109
+
110
+ if licence is None:
111
+ self.writer.writerow(row.keys())
112
+ else:
113
+ self.writer.writerow(row.values())
114
+
115
+ return row
116
+
117
+ def __enter__(self) -> typing.Any:
118
+ fname = secure_filename(
119
+ self.lmodel.getTitle(), only_ascii=self.options.only_ascii
120
+ )
121
+ self.csvpath = get_unique_path(f"{fname}.csv", self.destination)
122
+ self.cfh = self.csvpath.open("w")
123
+ self.writer = csv.writer(
124
+ self.cfh, delimiter=";", quotechar='"', quoting=csv.QUOTE_ALL
125
+ )
126
+
127
+ self.add_row(None, None)
128
+
129
+ return super().__enter__()
130
+
131
+ def __exit__(
132
+ self,
133
+ __exc_type: type[BaseException] | None,
134
+ __exc_value: BaseException | None,
135
+ __traceback: TracebackType | None,
136
+ ) -> bool | None:
137
+ self.cfh.close()
138
+ return super().__exit__(__exc_type, __exc_value, __traceback)
@@ -0,0 +1,49 @@
1
+ """Beschreibung
2
+
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2024 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ import json
12
+ import typing
13
+ from argparse import Namespace
14
+ from contextlib import AbstractContextManager
15
+ from types import TracebackType
16
+
17
+ from nl.export.plone import LicenceModel
18
+ from nl.export.utils import get_unique_path, secure_filename
19
+
20
+
21
+ class LFormatJSON(AbstractContextManager):
22
+ def __init__(self, lmodel: LicenceModel, options: Namespace) -> None:
23
+ self.lmodel = lmodel
24
+ self.options = options
25
+ self.destination = self.options.ablage.absolute()
26
+
27
+ self.jpath = None
28
+
29
+ def add_row(self, licence: dict | None, licencee: dict | None) -> dict:
30
+ fpath = self.jpath / f"{licencee.plone_item['uid']}.json"
31
+ with fpath.open("w") as jfh:
32
+ json.dump(licencee.plone_item, jfh)
33
+
34
+ def __enter__(self) -> typing.Any:
35
+ fname = secure_filename(
36
+ self.lmodel.getTitle(), only_ascii=self.options.only_ascii
37
+ )
38
+ self.jpath = get_unique_path(f"{fname}", self.destination)
39
+ self.jpath.mkdir(exist_ok=True)
40
+
41
+ return super().__enter__()
42
+
43
+ def __exit__(
44
+ self,
45
+ __exc_type: type[BaseException] | None,
46
+ __exc_value: BaseException | None,
47
+ __traceback: TracebackType | None,
48
+ ) -> bool | None:
49
+ return super().__exit__(__exc_type, __exc_value, __traceback)
@@ -0,0 +1,177 @@
1
+ """Beschreibung
2
+
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2024 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ import typing
12
+ from argparse import Namespace
13
+ from contextlib import AbstractContextManager
14
+ from types import TracebackType
15
+
16
+ from lxml import etree
17
+
18
+ from nl.export.plone import LicenceModel
19
+ from nl.export.utils import get_unique_path, get_wf_state, option_title, secure_filename
20
+
21
+
22
+ class LFormatXML(AbstractContextManager):
23
+ def __init__(self, lmodel: LicenceModel, options: Namespace) -> None:
24
+ self.lmodel = lmodel
25
+ self.options = options
26
+ self.destination = self.options.ablage.absolute()
27
+
28
+ self.xmlpath = None
29
+ self.xfh = None
30
+ self.dom = None
31
+
32
+ def add_row(self, licence: dict | None, licencee: dict | None) -> None:
33
+ match self.options.version:
34
+ case 2:
35
+ self.add_row_version_2(licence, licencee)
36
+ case _:
37
+ self.add_row_version_1(licence, licencee)
38
+
39
+ def add_row_version_1(self, licence: dict | None, licencee: dict | None) -> None:
40
+ NL_NAMESPACE = "http://www.nationallizenzen.de/ns/nl"
41
+ XNL = f"{{{NL_NAMESPACE}}}"
42
+ NSMAP = {None: NL_NAMESPACE}
43
+
44
+ def cenc(key, data):
45
+ val_node = etree.Element(XNL + key, nsmap=NSMAP)
46
+
47
+ if isinstance(data, (list, tuple)):
48
+ for entry in data:
49
+ token_node = etree.Element(XNL + "token", nsmap=NSMAP)
50
+ token_node.text = entry
51
+
52
+ val_node.append(token_node)
53
+ elif type(data) is dict:
54
+ pass
55
+ else:
56
+ val_node.text = data
57
+
58
+ return val_node
59
+
60
+ licencee = {} if licencee is None else licencee.plone_item
61
+
62
+ row = {}
63
+ row["user_name"] = licencee.get("uid", "")
64
+ row["status"] = get_wf_state(licencee)
65
+ row["title"] = licencee.get("title", "")
66
+ row["street"] = licencee.get("street", "")
67
+ row["zip"] = licencee.get("zip", "")
68
+ row["city"] = licencee.get("city", "")
69
+ row["county"] = option_title(licencee, "county")
70
+ row["country"] = option_title(licencee, "country")
71
+ row["telephone"] = licencee.get("telephone", "")
72
+ row["fax"] = licencee.get("fax", "")
73
+ row["email"] = licencee.get("email", "")
74
+ row["url"] = licencee.get("url", "")
75
+ row["contactperson"] = licencee.get("contactperson", "")
76
+ row["sigel"] = licencee.get("sigel", "")
77
+ row["ezb_id"] = licencee.get("ezb_id", [])
78
+ row["subscriber_group"] = option_title(licencee, "subscriper_group")
79
+ row["ipv4_allow"] = licencee.get("ipv4_allow", [])
80
+ row["ipv4_deny"] = []
81
+ row["shib_provider_id"] = licencee.get("shib_provider_id", "")
82
+ row["uid"] = licencee.get("UID", "")
83
+ row["mtime"] = licencee.get("modified", "")
84
+
85
+ inst_node = etree.Element(XNL + "institution", nsmap=NSMAP)
86
+ self.dom.append(inst_node)
87
+
88
+ for key, val in row.items():
89
+ val_node = cenc(key, val)
90
+ inst_node.append(val_node)
91
+
92
+ def add_row_version_2(self, licence: dict | None, licencee: dict | None) -> None:
93
+ NL_NAMESPACE = "http://www.nationallizenzen.de/ns/nl"
94
+ XNL = f"{{{NL_NAMESPACE}}}"
95
+ NSMAP = {None: NL_NAMESPACE}
96
+
97
+ def cenc(key, data):
98
+ val_node = etree.Element(XNL + key, nsmap=NSMAP)
99
+
100
+ if isinstance(data, (list, tuple)):
101
+ for entry in data:
102
+ token_node = etree.Element(XNL + "token", nsmap=NSMAP)
103
+ token_node.text = entry
104
+
105
+ val_node.append(token_node)
106
+ elif type(data) is dict:
107
+ pass
108
+ else:
109
+ val_node.text = data
110
+
111
+ return val_node
112
+
113
+ licencee = {} if licencee is None else licencee.plone_item
114
+
115
+ row = {}
116
+ row["user_name"] = licencee.get("uid", "")
117
+ row["status"] = get_wf_state(licencee)
118
+ row["title"] = licencee.get("title", "")
119
+ row["street"] = licencee.get("street", "")
120
+ row["zip"] = licencee.get("zip", "")
121
+ row["city"] = licencee.get("city", "")
122
+ row["county"] = option_title(licencee, "county")
123
+ row["country"] = option_title(licencee, "country")
124
+ row["telephone"] = licencee.get("telephone", "")
125
+ row["fax"] = licencee.get("fax", "")
126
+ row["email"] = licencee.get("email", "")
127
+ row["url"] = licencee.get("url", "")
128
+ row["contactperson"] = licencee.get("contactperson", "")
129
+ row["sigel"] = licencee.get("sigel", "")
130
+ row["ezb_id"] = licencee.get("ezb_id", [])
131
+ row["foreign_keys"] = licencee.get("foreign_keys", [])
132
+ row["isni"] = licencee.get("isni", [])
133
+ row["subscriber_group"] = option_title(licencee, "subscriper_group")
134
+ row["ipv4_allow"] = licencee.get("ipv4_allow", [])
135
+ row["ipv6"] = licencee.get("ipv6", [])
136
+ row["shib_provider_id"] = licencee.get("shib_provider_id", "")
137
+ row["uid"] = licencee.get("UID", "")
138
+ row["mtime"] = licencee.get("modified", "")
139
+
140
+ inst_node = etree.Element(XNL + "institution", nsmap=NSMAP)
141
+ self.dom.append(inst_node)
142
+
143
+ for key, val in row.items():
144
+ val_node = cenc(key, val)
145
+ inst_node.append(val_node)
146
+
147
+ def __enter__(self) -> typing.Any:
148
+ fname = secure_filename(
149
+ self.lmodel.getTitle(), only_ascii=self.options.only_ascii
150
+ )
151
+ self.xmlpath = get_unique_path(f"{fname}.xml", self.destination)
152
+
153
+ basexml = b"""<?xml version='1.0' encoding='UTF-8'?>"""
154
+ basexml += b"""<nl:institutions xmlns:nl="http://www.nationallizenzen.de/ns/nl"></nl:institutions>"""
155
+
156
+ self.dom = etree.fromstring(basexml)
157
+
158
+ return super().__enter__()
159
+
160
+ def __exit__(
161
+ self,
162
+ __exc_type: type[BaseException] | None,
163
+ __exc_value: BaseException | None,
164
+ __traceback: TracebackType | None,
165
+ ) -> bool | None:
166
+ with self.xmlpath.open("wb") as xfh:
167
+ xfh.write(
168
+ etree.tostring(
169
+ self.dom,
170
+ xml_declaration=True,
171
+ encoding="UTF-8",
172
+ method="xml",
173
+ pretty_print=True,
174
+ )
175
+ )
176
+
177
+ return super().__exit__(__exc_type, __exc_value, __traceback)
nl/export/gapi.py ADDED
@@ -0,0 +1,49 @@
1
+ # -*- coding: UTF-8 -*-
2
+ """API
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2023 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ # Imports
12
+
13
+
14
+ class TerminalColors:
15
+ RESET = "\033[0m"
16
+ BOLD = "\033[1m"
17
+ UNDERLINE = "\033[4m"
18
+
19
+ # Text colors
20
+ BLACK = "\033[30m"
21
+ RED = "\033[31m"
22
+ GREEN = "\033[32m"
23
+ YELLOW = "\033[33m"
24
+ BLUE = "\033[34m"
25
+ MAGENTA = "\033[35m"
26
+ CYAN = "\033[36m"
27
+ WHITE = "\033[37m"
28
+
29
+ # Background colors
30
+ BLACK_BG = "\033[40m"
31
+ RED_BG = "\033[41m"
32
+ GREEN_BG = "\033[42m"
33
+ YELLOW_BG = "\033[43m"
34
+ BLUE_BG = "\033[44m"
35
+ MAGENTA_BG = "\033[45m"
36
+ CYAN_BG = "\033[46m"
37
+ WHITE_BG = "\033[47m"
38
+
39
+ @classmethod
40
+ def bold(cls, msg: str) -> str:
41
+ return f"{cls.BOLD}{msg}{cls.RESET}"
42
+
43
+ @classmethod
44
+ def green(cls, msg: str) -> str:
45
+ return f"{cls.GREEN}{msg}{cls.RESET}"
46
+
47
+ @classmethod
48
+ def red(cls, msg: str) -> str:
49
+ return f"{cls.RED}{msg}{cls.RESET}"
@@ -0,0 +1,11 @@
1
+ # -*- coding: UTF-8 -*-
2
+ """Interfaces
3
+ ##############################################################################
4
+ #
5
+ # Copyright (c) 2023 Verbundzentrale des GBV.
6
+ # All Rights Reserved.
7
+ #
8
+ ##############################################################################
9
+ """
10
+
11
+ # Imports