okdata-cli 3.2.0__py3-none-any.whl → 4.1.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.
Files changed (28) hide show
  1. okdata/cli/__main__.py +6 -5
  2. okdata/cli/command.py +2 -2
  3. okdata/cli/commands/datasets/datasets.py +4 -0
  4. okdata/cli/commands/datasets/questions.py +5 -56
  5. okdata/cli/commands/datasets/wizards.py +0 -7
  6. okdata/cli/commands/permissions.py +15 -14
  7. okdata/cli/commands/pubs/__init__.py +3 -0
  8. okdata/cli/commands/{pubreg → pubs}/client.py +29 -4
  9. okdata/cli/commands/{pubreg/pubreg.py → pubs/pubs.py} +83 -57
  10. okdata/cli/commands/{pubreg → pubs}/questions.py +80 -21
  11. okdata/cli/commands/{pubreg → pubs}/wizards.py +29 -16
  12. okdata/cli/commands/{datasets/validators.py → validators.py} +32 -45
  13. okdata/cli/commands/wizard.py +8 -0
  14. okdata/cli/data/output-format/datasets_dataset_config.json +0 -1
  15. okdata/cli/output.py +3 -4
  16. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/METADATA +3 -3
  17. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/RECORD +27 -27
  18. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/WHEEL +1 -1
  19. okdata/cli/commands/pubreg/__init__.py +0 -3
  20. /okdata/cli/data/output-format/{pubreg_audit_log_config.json → pubs_audit_log_config.json} +0 -0
  21. /okdata/cli/data/output-format/{pubreg_clients_config.json → pubs_clients_config.json} +0 -0
  22. /okdata/cli/data/output-format/{pubreg_multiple_client_keys_config.json → pubs_multiple_client_keys_config.json} +0 -0
  23. /okdata/cli/data/output-format/{pubreg_single_client_keys_config.json → pubs_single_client_keys_config.json} +0 -0
  24. /okdata_cli-3.2.0-nspkg.pth → /okdata_cli-4.1.0-nspkg.pth +0 -0
  25. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/LICENSE +0 -0
  26. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/entry_points.txt +0 -0
  27. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/namespace_packages.txt +0 -0
  28. {okdata_cli-3.2.0.dist-info → okdata_cli-4.1.0.dist-info}/top_level.txt +0 -0
okdata/cli/__main__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import sys
3
3
 
4
- from keycloak.exceptions import KeycloakGetError
4
+ from keycloak.exceptions import KeycloakGetError, KeycloakPostError
5
5
  from okdata.sdk.exceptions import ApiAuthenticateError
6
6
  from requests.exceptions import RequestException
7
7
 
@@ -9,7 +9,7 @@ from okdata.cli import MAINTAINER
9
9
  from okdata.cli.command import BaseCommand
10
10
  from okdata.cli.commands.datasets import DatasetsCommand
11
11
  from okdata.cli.commands.permissions import PermissionsCommand
12
- from okdata.cli.commands.pubreg import PubregCommand
12
+ from okdata.cli.commands.pubs import PubsCommand
13
13
  from okdata.cli.commands.status import StatusCommand
14
14
  from okdata.cli.commands.teams.teams import TeamsCommand
15
15
 
@@ -40,11 +40,12 @@ def main():
40
40
  "An error occurred (ApiAuthenticateError): Invalid credentials",
41
41
  {"error": 1, "message": "Invalid credentials"},
42
42
  )
43
- except KeycloakGetError as e:
43
+ except (KeycloakGetError, KeycloakPostError) as e:
44
44
  error = json.loads(e.error_message)
45
+ error_type = e.__class__.__name__
45
46
  instance.log.info(f"Keycloak reported: {e}")
46
47
  instance.print(
47
- f"An error occurred (KeycloakGetError): {error['error_description']}"
48
+ f"An error occurred ({error_type}): {error['error_description']}"
48
49
  )
49
50
  except (EOFError, KeyboardInterrupt):
50
51
  instance.print("\nAbort.")
@@ -69,7 +70,7 @@ def get_command_class(argv):
69
70
  commands = {
70
71
  "datasets": DatasetsCommand,
71
72
  "permissions": PermissionsCommand,
72
- "pubreg": PubregCommand,
73
+ "pubs": PubsCommand,
73
74
  "status": StatusCommand,
74
75
  "teams": TeamsCommand,
75
76
  }
okdata/cli/command.py CHANGED
@@ -21,7 +21,7 @@ class BaseCommand:
21
21
  usage:
22
22
  okdata datasets [options]
23
23
  okdata permissions [options]
24
- okdata pubreg [options]
24
+ okdata pubs [options]
25
25
  okdata status [options]
26
26
  okdata teams [options]
27
27
  okdata -h | --help
@@ -29,7 +29,7 @@ usage:
29
29
  Commands available:
30
30
  datasets
31
31
  permissions
32
- pubreg
32
+ pubs
33
33
  status
34
34
  teams
35
35
 
@@ -292,6 +292,10 @@ Options:{BASE_COMMAND_OPTIONS}
292
292
  parts = dataset_uri.split("/")
293
293
  dataset_id, version, edition = parts + [None] * (3 - len(parts))
294
294
 
295
+ # First verify that the dataset exists; `get_dataset` raises an error
296
+ # if not.
297
+ self.sdk.get_dataset(dataset_id)
298
+
295
299
  if auto_resolve:
296
300
  if not version:
297
301
  version = self._get_latest_version(dataset_id)["version"]
@@ -1,21 +1,17 @@
1
- import csv
2
-
3
1
  from questionary import Choice
4
2
 
5
- from okdata.cli.commands.datasets.validators import (
3
+ from okdata.cli.commands.validators import (
6
4
  KeywordValidator,
7
- PhoneValidator,
8
5
  SimpleEmailValidator,
9
- SpatialResolutionValidator,
10
- SpatialValidator,
11
- StandardsValidator,
12
6
  TitleValidator,
13
7
  )
14
- from okdata.cli.commands.wizard import required_style
8
+ from okdata.cli.commands.wizard import filter_comma_separated, required_style
15
9
 
16
10
  pipeline_choices = {
17
11
  "file": [
18
12
  Choice("Lagre dataen slik den er", "data-copy"),
13
+ Choice("Konverter fra CSV til Delta", "csv-to-delta"),
14
+ Choice("Konverter fra JSON til Delta", "json-to-delta"),
19
15
  Choice("Konverter fra CSV til Parquet", "csv-to-parquet"),
20
16
  Choice("Konverter fra Excel til CSV", "pipeline-excel-to-csv"),
21
17
  Choice("Ingen prosessering (krever manuell konfigurasjon av pipeline)", False),
@@ -30,14 +26,7 @@ available_pipelines = [
30
26
  ]
31
27
 
32
28
 
33
- def filter_comma_separated(value):
34
- values = next(
35
- csv.reader([value], delimiter=",", escapechar="\\", skipinitialspace=True)
36
- )
37
- return [x.strip() for x in values if x]
38
-
39
-
40
- def qs_create(include_extra_metadata=True):
29
+ def qs_create():
41
30
  return [
42
31
  {
43
32
  **required_style,
@@ -67,38 +56,6 @@ def qs_create(include_extra_metadata=True):
67
56
  "validate": KeywordValidator,
68
57
  "filter": filter_comma_separated,
69
58
  },
70
- {
71
- **required_style,
72
- "type": "confirm",
73
- "name": "contains_geodata",
74
- "message": "Inneholder datasettet geodata?",
75
- "default": False,
76
- "when": lambda x: include_extra_metadata,
77
- },
78
- {
79
- "type": "text",
80
- "name": "spatial",
81
- "message": "Romlig avgrensning (komma-separert)",
82
- "validate": SpatialValidator,
83
- "filter": filter_comma_separated,
84
- "when": lambda x: include_extra_metadata and x["contains_geodata"],
85
- },
86
- {
87
- "type": "text",
88
- "name": "spatialResolutionInMeters",
89
- "message": "Romlig oppløsning (i meter)",
90
- "validate": SpatialResolutionValidator,
91
- "filter": lambda v: float(v.replace(",", ".")) if v else None,
92
- "when": lambda x: include_extra_metadata and x["contains_geodata"],
93
- },
94
- {
95
- "type": "text",
96
- "name": "conformsTo",
97
- "message": "I samsvar med standarder (komma-separert)",
98
- "validate": StandardsValidator,
99
- "filter": filter_comma_separated,
100
- "when": lambda x: include_extra_metadata,
101
- },
102
59
  {
103
60
  **required_style,
104
61
  "type": "select",
@@ -138,7 +95,6 @@ def qs_create(include_extra_metadata=True):
138
95
  "http://creativecommons.org/publicdomain/zero/1.0/",
139
96
  ),
140
97
  ],
141
- "when": lambda x: include_extra_metadata,
142
98
  },
143
99
  {"type": "text", "name": "name", "message": "Kontaktperson – navn"},
144
100
  {
@@ -148,13 +104,6 @@ def qs_create(include_extra_metadata=True):
148
104
  "message": "Kontaktperson – epost",
149
105
  "validate": SimpleEmailValidator,
150
106
  },
151
- {
152
- **required_style,
153
- "type": "text",
154
- "name": "phone",
155
- "message": "Kontaktperson – telefon",
156
- "validate": PhoneValidator,
157
- },
158
107
  {"type": "text", "name": "publisher", "message": "Utgiver"},
159
108
  {
160
109
  **required_style,
@@ -29,17 +29,10 @@ class DatasetCreateWizard:
29
29
  "contactPoint": {
30
30
  "name": choices["name"],
31
31
  "email": choices["email"],
32
- "phone": choices["phone"],
33
32
  },
34
33
  "publisher": choices["publisher"],
35
34
  }
36
35
 
37
- if choices.get("spatial"):
38
- config["spatial"] = choices["spatial"]
39
- if choices.get("spatialResolutionInMeters"):
40
- config["spatialResolutionInMeters"] = choices["spatialResolutionInMeters"]
41
- if choices.get("conformsTo"):
42
- config["conformsTo"] = choices["conformsTo"]
43
36
  if choices.get("license"):
44
37
  config["license"] = choices["license"]
45
38
 
@@ -12,12 +12,13 @@ class PermissionsCommand(BaseCommand):
12
12
 
13
13
  Usage:
14
14
  okdata permissions ls [<resource_name>] [options]
15
- okdata permissions add <resource_name> <user> <scope> [--team | --client] [options]
15
+ okdata permissions add <resource_name> <user> [<scope>] [--team | --client] [options]
16
16
  okdata permissions rm <resource_name> <user> [<scope>] [--team | --client] [options]
17
17
 
18
18
  Examples:
19
19
  okdata permissions ls
20
20
  okdata permissions ls okdata:dataset:my-dataset
21
+ okdata permissions add okdata:dataset:my-dataset janedoe
21
22
  okdata permissions add okdata:dataset:my-dataset janedoe okdata:dataset:read
22
23
  okdata permissions rm okdata:dataset:my-dataset janedoe
23
24
  okdata permissions rm okdata:dataset:my-dataset janedoe okdata:dataset:write
@@ -57,10 +58,10 @@ Options:{BASE_COMMAND_OPTIONS}
57
58
  ]
58
59
  if self.cmd("add"):
59
60
  self.add_user(resource_name, user_class(user), scope)
60
- self.print("Granted {} on '{}' for {} '{}'".format(*fmt_args))
61
+ self.print("Granted {} on '{}' to {} '{}'".format(*fmt_args))
61
62
  else:
62
63
  self.remove_user(resource_name, user_class(user), scope)
63
- self.print("Revoked {} on '{}' for {} '{}'".format(*fmt_args))
64
+ self.print("Revoked {} on '{}' from {} '{}'".format(*fmt_args))
64
65
 
65
66
  def list_my_permissions(self):
66
67
  """Print all permissions for the current user."""
@@ -99,9 +100,14 @@ Options:{BASE_COMMAND_OPTIONS}
99
100
  out.add_rows(sorted(results, key=itemgetter("user_type", "user_name")))
100
101
  self.print(f"Permissions for '{resource_name}'", out)
101
102
 
102
- def add_user(self, resource_name, user, scope):
103
- """Grant `scope` on `resource_name` to `user`."""
104
- self.client.update_permission(resource_name, scope, add_users=[user])
103
+ def add_user(self, resource_name, user, scope=None):
104
+ """Grant `scope` on `resource_name` to `user`.
105
+
106
+ When `scope` is unspecified, grant every permission on `resource_name`.
107
+ """
108
+ return self.client.update_permission(
109
+ resource_name, scope or "__all__", add_users=[user]
110
+ )
105
111
 
106
112
  def remove_user(self, resource_name, user, scope=None):
107
113
  """Revoke `scope` on `resource_name` for `user`.
@@ -109,11 +115,6 @@ Options:{BASE_COMMAND_OPTIONS}
109
115
  When `scope` is unspecified, revoke every permission on `resource_name`
110
116
  for `user`.
111
117
  """
112
- if scope:
113
- self.client.update_permission(resource_name, scope, remove_users=[user])
114
- else:
115
- for permission in self.client.get_permissions(resource_name):
116
- if user.user_id in permission[f"{user.user_type}s"]:
117
- self.client.update_permission(
118
- resource_name, permission["scope"], remove_users=[user]
119
- )
118
+ return self.client.update_permission(
119
+ resource_name, scope or "__all__", remove_users=[user]
120
+ )
@@ -0,0 +1,3 @@
1
+ from okdata.cli.commands.pubs.pubs import PubsCommand
2
+
3
+ __all__ = ["PubsCommand"]
@@ -5,23 +5,48 @@ from okdata.sdk import SDK
5
5
  log = logging.getLogger()
6
6
 
7
7
 
8
- class PubregClient(SDK):
8
+ class PubsClient(SDK):
9
9
  def __init__(self, config=None, auth=None, env=None):
10
- self.__name__ = "pubreg"
10
+ self.__name__ = "pubs"
11
11
  super().__init__(config, auth, env)
12
12
  self.api_url = "https://api.data{}.oslo.systems/maskinporten".format(
13
13
  "-dev" if self.config.config["env"] == "dev" else ""
14
14
  )
15
15
 
16
- def create_client(self, team_id, provider, integration, scopes, env):
16
+ def create_maskinporten_client(self, team_id, provider, integration, scopes, env):
17
17
  data = {
18
+ "client_type": "maskinporten",
18
19
  "team_id": team_id,
19
20
  "provider": provider,
20
21
  "integration": integration,
21
22
  "scopes": scopes,
22
23
  "env": env,
23
24
  }
24
- log.info(f"Creating client with payload: {data}")
25
+ log.info(f"Creating Maskinporten client with payload: {data}")
26
+ return self.post(f"{self.api_url}/clients", data=data).json()
27
+
28
+ def create_idporten_client(
29
+ self,
30
+ team_id,
31
+ integration,
32
+ client_uri,
33
+ frontchannel_logout_uri,
34
+ redirect_uris,
35
+ post_logout_redirect_uris,
36
+ env,
37
+ ):
38
+ data = {
39
+ "client_type": "idporten",
40
+ "team_id": team_id,
41
+ "provider": "idporten",
42
+ "integration": integration,
43
+ "client_uri": client_uri,
44
+ "frontchannel_logout_uri": frontchannel_logout_uri,
45
+ "redirect_uris": redirect_uris,
46
+ "post_logout_redirect_uris": post_logout_redirect_uris,
47
+ "env": env,
48
+ }
49
+ log.info(f"Creating ID-porten client with payload: {data}")
25
50
  return self.post(f"{self.api_url}/clients", data=data).json()
26
51
 
27
52
  def get_clients(self, env):
@@ -6,9 +6,14 @@ from okdata.sdk.team.client import TeamClient
6
6
 
7
7
  from okdata.cli import MAINTAINER
8
8
  from okdata.cli.command import BASE_COMMAND_OPTIONS, BaseCommand
9
- from okdata.cli.commands.pubreg.client import PubregClient
10
- from okdata.cli.commands.pubreg.questions import NoClientsError, NoKeysError
11
- from okdata.cli.commands.pubreg.wizards import (
9
+ from okdata.cli.commands.pubs.client import PubsClient
10
+ from okdata.cli.commands.pubs.questions import (
11
+ NoClientsError,
12
+ NoKeysError,
13
+ client_types,
14
+ providers,
15
+ )
16
+ from okdata.cli.commands.pubs.wizards import (
12
17
  audit_log_wizard,
13
18
  create_client_wizard,
14
19
  create_key_wizard,
@@ -21,33 +26,33 @@ from okdata.cli.commands.teams.questions import NoTeamError
21
26
  from okdata.cli.output import create_output
22
27
 
23
28
 
24
- class PubregCommand(BaseCommand):
25
- __doc__ = f"""Oslo :: Public registers
29
+ class PubsCommand(BaseCommand):
30
+ __doc__ = f"""Oslo :: Public services
26
31
 
27
32
  Usage:
28
- okdata pubreg create-client [options]
29
- okdata pubreg list-clients [options]
30
- okdata pubreg delete-client [options]
31
- okdata pubreg create-key [options]
32
- okdata pubreg list-keys [options]
33
- okdata pubreg delete-key [options]
34
- okdata pubreg audit-log [options]
33
+ okdata pubs create-client [options]
34
+ okdata pubs list-clients [options]
35
+ okdata pubs delete-client [options]
36
+ okdata pubs create-key [options]
37
+ okdata pubs list-keys [options]
38
+ okdata pubs delete-key [options]
39
+ okdata pubs audit-log [options]
35
40
 
36
41
  Examples:
37
- okdata pubreg create-client
38
- okdata pubreg list-clients
39
- okdata pubreg delete-client
40
- okdata pubreg create-key
41
- okdata pubreg list-keys
42
- okdata pubreg delete-key
43
- okdata pubreg audit-log
42
+ okdata pubs create-client
43
+ okdata pubs list-clients
44
+ okdata pubs delete-client
45
+ okdata pubs create-key
46
+ okdata pubs list-keys
47
+ okdata pubs delete-key
48
+ okdata pubs audit-log
44
49
 
45
50
  Options:{BASE_COMMAND_OPTIONS}
46
51
  """
47
52
 
48
53
  def __init__(self):
49
54
  super().__init__()
50
- self.pubreg_client = PubregClient(env=self.opt("env"))
55
+ self.pubs_client = PubsClient(env=self.opt("env"))
51
56
  self.team_client = TeamClient(env=self.opt("env"))
52
57
 
53
58
  def handler(self):
@@ -77,40 +82,55 @@ Options:{BASE_COMMAND_OPTIONS}
77
82
  return
78
83
 
79
84
  team_id = config["team_id"]
85
+ client_type_id = config["client_type_id"]
80
86
  provider_id = config["provider_id"]
81
- provider_name = config["provider_name"]
82
87
  integration = config["integration"]
83
88
  scopes = config["scopes"]
84
89
  env = config["env"]
85
90
 
86
91
  self.confirm_to_continue(
87
- f"Will create a new client for {provider_name} in {env} with "
88
- f"scopes {scopes}."
92
+ "Will create a new {} client{} in {}{}.".format(
93
+ client_types[client_type_id],
94
+ f" for {providers[provider_id]}" if provider_id else "",
95
+ env,
96
+ f" with scopes {scopes}" if scopes else "",
97
+ )
89
98
  )
90
99
 
91
100
  self.print("Creating client...")
92
- response = self.pubreg_client.create_client(
93
- team_id, provider_id, integration, scopes, env
94
- )
101
+ if client_type_id == "maskinporten":
102
+ response = self.pubs_client.create_maskinporten_client(
103
+ team_id, provider_id, integration, scopes, env
104
+ )
105
+ else:
106
+ response = self.pubs_client.create_idporten_client(
107
+ team_id,
108
+ integration,
109
+ config["client_uri"],
110
+ config["frontchannel_logout_uri"],
111
+ config["redirect_uris"],
112
+ config["post_logout_redirect_uris"],
113
+ env,
114
+ )
95
115
  client_name = response["client_name"]
96
116
  self.print(
97
117
  f"""
98
118
  Done! Created a new client '{client_name}'.
99
119
  You may now go ahead and create a key for it by running:
100
120
 
101
- okdata pubreg create-key"""
121
+ okdata pubs create-key"""
102
122
  )
103
123
 
104
124
  def list_clients(self):
105
125
  config = list_clients_wizard()
106
126
  env = config["env"]
107
- clients = self.pubreg_client.get_clients(env)
108
- out = create_output(self.opt("format"), "pubreg_clients_config.json")
127
+ clients = self.pubs_client.get_clients(env)
128
+ out = create_output(self.opt("format"), "pubs_clients_config.json")
109
129
  out.add_rows(sorted(clients, key=itemgetter("client_name")))
110
130
  self.print(f"Clients in {env}:", out)
111
131
 
112
132
  def delete_client(self):
113
- choices = delete_client_wizard(self.pubreg_client)
133
+ choices = delete_client_wizard(self.pubs_client)
114
134
  env = choices["env"]
115
135
  client_id = choices["client_id"]
116
136
  client_name = choices["client_name"]
@@ -123,16 +143,18 @@ You may now go ahead and create a key for it by running:
123
143
  client_name,
124
144
  env,
125
145
  (
126
- f" along with the key stored in AWS account {aws_account} "
127
- f"({aws_region})"
128
- )
129
- if delete_from_aws
130
- else "",
146
+ (
147
+ f" along with the key stored in AWS account {aws_account} "
148
+ f"({aws_region})"
149
+ )
150
+ if delete_from_aws
151
+ else ""
152
+ ),
131
153
  ),
132
154
  )
133
155
 
134
156
  self.print(f"Deleting client '{client_name}' [{env}]...")
135
- res = self.pubreg_client.delete_client(env, client_id, aws_account, aws_region)
157
+ res = self.pubs_client.delete_client(env, client_id, aws_account, aws_region)
136
158
  deleted_ssm_params = res["deleted_ssm_params"]
137
159
 
138
160
  self.print("\nDone! The client is deleted and will no longer work.")
@@ -203,11 +225,11 @@ You may now go ahead and create a key for it by running:
203
225
 
204
226
  def create_client_key(self):
205
227
  try:
206
- config = create_key_wizard(self.pubreg_client)
228
+ config = create_key_wizard(self.pubs_client)
207
229
  except NoClientsError:
208
230
  self.print(
209
231
  "No clients in the given environment yet!\n\n"
210
- " Create one with `okdata pubreg create-client`.\n"
232
+ " Create one with `okdata pubs create-client`.\n"
211
233
  )
212
234
  return
213
235
 
@@ -226,22 +248,26 @@ You may now go ahead and create a key for it by running:
226
248
  client_name,
227
249
  env,
228
250
  (
229
- f"send it to AWS account {aws_account} ({aws_region}), "
230
- "REPLACING any existing key for this client"
231
- )
232
- if key_destination == "aws"
233
- else "save it locally",
251
+ (
252
+ f"send it to AWS account {aws_account} ({aws_region}), "
253
+ "REPLACING any existing key for this client"
254
+ )
255
+ if key_destination == "aws"
256
+ else "save it locally"
257
+ ),
258
+ ),
259
+ (
260
+ "The key will be rotated automatically every night on weekdays.\n"
261
+ if enable_auto_rotate
262
+ else "The key will NOT be rotated automatically.\n"
234
263
  ),
235
- "The key will be rotated automatically every night on weekdays.\n"
236
- if enable_auto_rotate
237
- else "The key will NOT be rotated automatically.\n",
238
264
  ]
239
265
  )
240
266
  )
241
267
 
242
268
  self.print("Creating key for '{}' [{}]...".format(client_name, env))
243
269
 
244
- key = self.pubreg_client.create_key(
270
+ key = self.pubs_client.create_key(
245
271
  env, client_id, aws_account, aws_region, enable_auto_rotate
246
272
  )
247
273
 
@@ -256,10 +282,10 @@ You may now go ahead and create a key for it by running:
256
282
  )
257
283
 
258
284
  def _list_client_keys_single(self, client_id, client_name, env):
259
- keys = self.pubreg_client.get_keys(env, client_id)
285
+ keys = self.pubs_client.get_keys(env, client_id)
260
286
  out = create_output(
261
287
  self.opt("format"),
262
- "pubreg_single_client_keys_config.json",
288
+ "pubs_single_client_keys_config.json",
263
289
  )
264
290
  out.add_rows(sorted(keys, key=itemgetter("expires")))
265
291
  self.print(f"Keys for client {client_name} [{env}]:", out)
@@ -269,17 +295,17 @@ You may now go ahead and create a key for it by running:
269
295
  keys = [
270
296
  {**key, "client_name": client["name"]}
271
297
  for client in clients
272
- for key in self.pubreg_client.get_keys(env, client["id"])
298
+ for key in self.pubs_client.get_keys(env, client["id"])
273
299
  ]
274
300
  out = create_output(
275
301
  self.opt("format"),
276
- "pubreg_multiple_client_keys_config.json",
302
+ "pubs_multiple_client_keys_config.json",
277
303
  )
278
304
  out.add_rows(sorted(keys, key=itemgetter("expires")))
279
305
  self.print(f"All client keys [{env}]:", out)
280
306
 
281
307
  def list_client_keys(self):
282
- choices = list_keys_wizard(self.pubreg_client)
308
+ choices = list_keys_wizard(self.pubs_client)
283
309
  env = choices["env"]
284
310
 
285
311
  if "clients" in choices:
@@ -291,7 +317,7 @@ You may now go ahead and create a key for it by running:
291
317
 
292
318
  def delete_client_key(self):
293
319
  try:
294
- choices = delete_key_wizard(self.pubreg_client)
320
+ choices = delete_key_wizard(self.pubs_client)
295
321
  except NoKeysError:
296
322
  self.print("The selected client doesn't have any keys.")
297
323
  return
@@ -306,17 +332,17 @@ You may now go ahead and create a key for it by running:
306
332
  )
307
333
 
308
334
  self.print(f"Deleting key '{key_id}' from '{client_name}' [{env}]...")
309
- self.pubreg_client.delete_key(env, client_id, key_id)
335
+ self.pubs_client.delete_key(env, client_id, key_id)
310
336
  self.print("Done! The key is deleted and will no longer work.")
311
337
 
312
338
  def audit_log(self):
313
- choices = audit_log_wizard(self.pubreg_client)
339
+ choices = audit_log_wizard(self.pubs_client)
314
340
  env = choices["env"]
315
341
  client_id = choices["client_id"]
316
342
  client_name = choices["client_name"]
317
343
 
318
- audit_log = self.pubreg_client.get_audit_log(env, client_id)
344
+ audit_log = self.pubs_client.get_audit_log(env, client_id)
319
345
 
320
- out = create_output(self.opt("format"), "pubreg_audit_log_config.json")
346
+ out = create_output(self.opt("format"), "pubs_audit_log_config.json")
321
347
  out.add_rows(sorted(audit_log, key=itemgetter("timestamp")))
322
348
  self.print(f"Audit log for client {client_name} [{env}]:", out)
@@ -1,11 +1,21 @@
1
- import re
2
1
  from operator import itemgetter
3
2
 
4
3
  from questionary import Choice
5
4
 
6
- from okdata.cli.commands.wizard import required_style
5
+ from okdata.cli.commands.validators import (
6
+ AWSAccountValidator,
7
+ IntegrationValidator,
8
+ URIListValidator,
9
+ URIValidator,
10
+ )
11
+ from okdata.cli.commands.wizard import filter_comma_separated, required_style
12
+
13
+ client_types = {
14
+ "idporten": "ID-porten",
15
+ "maskinporten": "Maskinporten",
16
+ }
7
17
 
8
- _providers = {
18
+ providers = {
9
19
  "freg": "Folkeregisteret",
10
20
  "krr": "Kontaktregisteret",
11
21
  "skatt": "Skatteetaten",
@@ -62,18 +72,29 @@ def q_env():
62
72
  **required_style,
63
73
  "type": "select",
64
74
  "name": "env",
65
- "message": "Maskinporten environment",
75
+ "message": "Environment",
66
76
  "choices": _environments,
67
77
  }
68
78
 
69
79
 
80
+ def q_client_type():
81
+ return {
82
+ **required_style,
83
+ "type": "select",
84
+ "name": "client_type_id",
85
+ "message": "Client type",
86
+ "choices": [Choice(pname, pid) for pid, pname in client_types.items()],
87
+ }
88
+
89
+
70
90
  def q_provider():
71
91
  return {
72
92
  **required_style,
73
93
  "type": "select",
74
94
  "name": "provider_id",
75
95
  "message": "Provider",
76
- "choices": [Choice(pname, pid) for pid, pname in _providers.items()],
96
+ "choices": [Choice(pname, pid) for pid, pname in providers.items()],
97
+ "when": lambda x: x.get("client_type_id") == "maskinporten",
77
98
  }
78
99
 
79
100
 
@@ -83,19 +104,13 @@ def q_scopes():
83
104
  "type": "checkbox",
84
105
  "name": "scopes",
85
106
  "message": "Scopes",
86
- "choices": lambda x: _scopes[x["provider_id"]],
107
+ "choices": lambda x: _scopes[x["provider_id"]] if "provider_id" in x else [],
87
108
  "validate": (lambda choices: bool(choices) or "Select at least one scope"),
109
+ "when": lambda x: x.get("client_type_id") == "maskinporten",
88
110
  }
89
111
 
90
112
 
91
113
  def q_integration():
92
- def _validate_integration(text):
93
- if len(text) > 30:
94
- return "Too long!"
95
- if not re.fullmatch("[0-9a-z-]+", text):
96
- return 'Only lowercase letters, numbers and "-", please'
97
- return True
98
-
99
114
  return {
100
115
  **required_style,
101
116
  "type": "text",
@@ -104,13 +119,59 @@ def q_integration():
104
119
  "instruction": (
105
120
  "(identifying in which system or case this client will be used)"
106
121
  ),
107
- "validate": _validate_integration,
122
+ "validate": IntegrationValidator,
108
123
  }
109
124
 
110
125
 
111
- def q_client(pubreg_client, allow_all=False):
126
+ def q_redirect_uris():
127
+ return {
128
+ **required_style,
129
+ "type": "text",
130
+ "name": "redirect_uris",
131
+ "message": "Redirect URIs (comma-separated)",
132
+ "filter": filter_comma_separated,
133
+ "when": lambda x: x.get("client_type_id") == "idporten",
134
+ "validate": URIListValidator,
135
+ }
136
+
137
+
138
+ def q_post_logout_redirect_uris():
139
+ return {
140
+ **required_style,
141
+ "type": "text",
142
+ "name": "post_logout_redirect_uris",
143
+ "message": "Post logout Redirect URIs (comma-separated)",
144
+ "filter": filter_comma_separated,
145
+ "when": lambda x: x.get("client_type_id") == "idporten",
146
+ "validate": URIListValidator,
147
+ }
148
+
149
+
150
+ def q_frontchannel_logout_uri():
151
+ return {
152
+ **required_style,
153
+ "type": "text",
154
+ "name": "frontchannel_logout_uri",
155
+ "message": "Frontchannel logout URI",
156
+ "when": lambda x: x.get("client_type_id") == "idporten",
157
+ "validate": URIValidator,
158
+ }
159
+
160
+
161
+ def q_client_uri():
162
+ return {
163
+ **required_style,
164
+ "type": "text",
165
+ "name": "client_uri",
166
+ "message": "Client URI (back URI)",
167
+ "when": lambda x: x.get("client_type_id") == "idporten",
168
+ "validate": URIValidator,
169
+ }
170
+
171
+
172
+ def q_client(pubs_client, allow_all=False):
112
173
  def _client_choices(env):
113
- clients = pubreg_client.get_clients(env)
174
+ clients = pubs_client.get_clients(env)
114
175
 
115
176
  if not clients:
116
177
  raise NoClientsError
@@ -165,9 +226,7 @@ def q_aws_account():
165
226
  "name": "aws_account",
166
227
  "message": "AWS account number",
167
228
  "when": lambda x: x.get("key_destination") == "aws" or x.get("delete_from_aws"),
168
- "validate": (
169
- lambda t: bool(re.fullmatch("[0-9]{12}", t)) or "12 digits, please"
170
- ),
229
+ "validate": AWSAccountValidator,
171
230
  }
172
231
 
173
232
 
@@ -198,9 +257,9 @@ def q_enable_auto_rotate():
198
257
  }
199
258
 
200
259
 
201
- def q_key(pubreg_client):
260
+ def q_key(pubs_client):
202
261
  def _key_choices(env, client_id):
203
- keys = pubreg_client.get_keys(env, client_id)
262
+ keys = pubs_client.get_keys(env, client_id)
204
263
 
205
264
  if not keys:
206
265
  raise NoKeysError
@@ -1,15 +1,19 @@
1
- from okdata.cli.commands.pubreg.questions import (
2
- _providers,
1
+ from okdata.cli.commands.pubs.questions import (
3
2
  q_aws_account,
4
3
  q_aws_region,
5
4
  q_client,
5
+ q_client_type,
6
+ q_client_uri,
6
7
  q_delete_from_aws,
7
8
  q_enable_auto_rotate,
8
9
  q_env,
10
+ q_frontchannel_logout_uri,
9
11
  q_integration,
10
12
  q_key,
11
13
  q_key_destination,
14
+ q_post_logout_redirect_uris,
12
15
  q_provider,
16
+ q_redirect_uris,
13
17
  q_scopes,
14
18
  )
15
19
  from okdata.cli.commands.teams.questions import q_team
@@ -20,17 +24,26 @@ def create_client_wizard(team_client):
20
24
  choices = run_questionnaire(
21
25
  q_env(),
22
26
  q_team(team_client),
27
+ q_client_type(),
23
28
  q_provider(),
24
29
  q_scopes(),
25
30
  q_integration(),
31
+ q_redirect_uris(),
32
+ q_post_logout_redirect_uris(),
33
+ q_frontchannel_logout_uri(),
34
+ q_client_uri(),
26
35
  )
27
36
  return {
28
37
  "env": choices["env"],
29
38
  "team_id": choices.get("team_id"),
30
- "provider_id": choices["provider_id"],
31
- "provider_name": _providers[choices["provider_id"]],
39
+ "client_type_id": choices["client_type_id"],
40
+ "provider_id": choices.get("provider_id"),
32
41
  "integration": choices["integration"],
33
- "scopes": choices["scopes"],
42
+ "scopes": choices.get("scopes"),
43
+ "redirect_uris": choices.get("redirect_uris"),
44
+ "post_logout_redirect_uris": choices.get("post_logout_redirect_uris"),
45
+ "frontchannel_logout_uri": choices.get("frontchannel_logout_uri"),
46
+ "client_uri": choices.get("client_uri"),
34
47
  }
35
48
 
36
49
 
@@ -39,10 +52,10 @@ def list_clients_wizard():
39
52
  return {"env": choices["env"]}
40
53
 
41
54
 
42
- def delete_client_wizard(pubreg_client):
55
+ def delete_client_wizard(pubs_client):
43
56
  choices = run_questionnaire(
44
57
  q_env(),
45
- q_client(pubreg_client),
58
+ q_client(pubs_client),
46
59
  q_delete_from_aws(),
47
60
  q_aws_account(),
48
61
  q_aws_region(),
@@ -57,10 +70,10 @@ def delete_client_wizard(pubreg_client):
57
70
  }
58
71
 
59
72
 
60
- def create_key_wizard(pubreg_client):
73
+ def create_key_wizard(pubs_client):
61
74
  choices = run_questionnaire(
62
75
  q_env(),
63
- q_client(pubreg_client),
76
+ q_client(pubs_client),
64
77
  q_key_destination(),
65
78
  q_aws_account(),
66
79
  q_aws_region(),
@@ -77,8 +90,8 @@ def create_key_wizard(pubreg_client):
77
90
  }
78
91
 
79
92
 
80
- def list_keys_wizard(pubreg_client):
81
- choices = run_questionnaire(q_env(), q_client(pubreg_client, True))
93
+ def list_keys_wizard(pubs_client):
94
+ choices = run_questionnaire(q_env(), q_client(pubs_client, True))
82
95
  return {
83
96
  "env": choices["env"],
84
97
  **(
@@ -94,11 +107,11 @@ def list_keys_wizard(pubreg_client):
94
107
  }
95
108
 
96
109
 
97
- def delete_key_wizard(pubreg_client):
110
+ def delete_key_wizard(pubs_client):
98
111
  choices = run_questionnaire(
99
112
  q_env(),
100
- q_client(pubreg_client),
101
- q_key(pubreg_client),
113
+ q_client(pubs_client),
114
+ q_key(pubs_client),
102
115
  )
103
116
  return {
104
117
  "env": choices["env"],
@@ -108,8 +121,8 @@ def delete_key_wizard(pubreg_client):
108
121
  }
109
122
 
110
123
 
111
- def audit_log_wizard(pubreg_client):
112
- choices = run_questionnaire(q_env(), q_client(pubreg_client))
124
+ def audit_log_wizard(pubs_client):
125
+ choices = run_questionnaire(q_env(), q_client(pubs_client))
113
126
  return {
114
127
  "env": choices["env"],
115
128
  "client_id": choices["client"]["id"],
@@ -1,6 +1,8 @@
1
- import re
2
1
  import csv
3
2
  import datetime
3
+ import re
4
+ from types import SimpleNamespace
5
+ from urllib.parse import urlparse
4
6
 
5
7
  from questionary import Validator, ValidationError
6
8
 
@@ -31,15 +33,6 @@ class SimpleEmailValidator(Validator):
31
33
  )
32
34
 
33
35
 
34
- class PhoneValidator(Validator):
35
- def validate(self, document):
36
- if not re.match(r"^[0-9]+$", document.text):
37
- raise ValidationError(
38
- message="Please enter a valid phone - all numbers and no space, example: 232334455",
39
- cursor_position=len(document.text),
40
- )
41
-
42
-
43
36
  class TitleValidator(Validator):
44
37
  def validate(self, document):
45
38
  if len(document.text) < 5:
@@ -68,55 +61,49 @@ class KeywordValidator(Validator):
68
61
  )
69
62
 
70
63
 
71
- class StandardsValidator(Validator):
64
+ class IntegrationValidator(Validator):
72
65
  def validate(self, document):
73
- standards = csv.reader(
74
- [document.text], delimiter=",", escapechar="\\", skipinitialspace=True
75
- )
76
- standards = [x.strip() for x in next(standards)]
77
- for standard in standards:
78
- if len(standard) < 3:
79
- raise ValidationError(
80
- message="Each standard reference must be at least 3 characters",
81
- cursor_position=len(document.text),
82
- )
83
- if len(standards) != len(set(standards)):
66
+ if len(document.text) > 30:
84
67
  raise ValidationError(
85
- message="Each standard reference must be unique",
68
+ message="Too long!", cursor_position=len(document.text)
69
+ )
70
+ if not re.fullmatch("[0-9a-z-]+", document.text):
71
+ raise ValidationError(
72
+ message='Only lowercase letters, numbers and "-", please',
86
73
  cursor_position=len(document.text),
87
74
  )
88
75
 
89
76
 
90
- class SpatialValidator(Validator):
77
+ class AWSAccountValidator(Validator):
91
78
  def validate(self, document):
92
- locations = csv.reader(
93
- [document.text], delimiter=",", escapechar="\\", skipinitialspace=True
94
- )
95
- locations = [x.strip() for x in next(locations)]
96
- for location in locations:
97
- if len(location) < 1:
98
- raise ValidationError(
99
- message="Each location must be at least 1 character",
100
- cursor_position=len(document.text),
101
- )
102
- if len(locations) != len(set(locations)):
79
+ if not re.fullmatch("[0-9]{12}", document.text):
80
+ raise ValidationError(
81
+ message="12 digits, please", cursor_position=len(document.text)
82
+ )
83
+
84
+
85
+ class URIValidator(Validator):
86
+ def validate(self, document):
87
+ parsed = urlparse(document.text)
88
+
89
+ if not (parsed.scheme and parsed.netloc):
103
90
  raise ValidationError(
104
- message="Each location must be unique",
91
+ message="Please enter a valid URI, including scheme (e.g. https://...)",
105
92
  cursor_position=len(document.text),
106
93
  )
107
94
 
108
95
 
109
- class SpatialResolutionValidator(Validator):
96
+ class URIListValidator(Validator):
110
97
  def validate(self, document):
111
- if not document.text:
112
- return None
98
+ uri_validator = URIValidator()
113
99
  try:
114
- number = float(document.text.replace(",", "."))
115
- if number <= 0:
116
- raise ValueError
117
- except ValueError:
100
+ for val in document.text.split(","):
101
+ uri_validator.validate(SimpleNamespace(text=val))
102
+ except ValidationError:
118
103
  raise ValidationError(
119
- message="Please enter a positive (decimal) number",
104
+ message=(
105
+ "Please enter a comma-separated list of URIs, including scheme "
106
+ "(e.g. https://...)"
107
+ ),
120
108
  cursor_position=len(document.text),
121
109
  )
122
- return None
@@ -1,3 +1,4 @@
1
+ import csv
1
2
  import sys
2
3
 
3
4
  from prompt_toolkit.styles import Style
@@ -17,3 +18,10 @@ def run_questionnaire(*questions):
17
18
  sys.exit()
18
19
 
19
20
  return choices
21
+
22
+
23
+ def filter_comma_separated(value):
24
+ values = next(
25
+ csv.reader([value], delimiter=",", escapechar="\\", skipinitialspace=True)
26
+ )
27
+ return [x.strip() for x in values if x]
@@ -16,7 +16,6 @@
16
16
  "key": "contactPoint",
17
17
  "fields": [
18
18
  "name",
19
- "phone",
20
19
  "email"
21
20
  ]
22
21
  }
okdata/cli/output.py CHANGED
@@ -41,12 +41,11 @@ class TableOutput(PrettyTable):
41
41
  super().__init__(column_headers)
42
42
 
43
43
  def field_values(self, row, row_key, key):
44
- value = ""
44
+ values = []
45
45
  for field in self.config[key]["fields"]:
46
46
  if field in row[row_key]:
47
- tmp = row[row_key][field]
48
- value += f"{tmp}\n"
49
- return value
47
+ values.append(str(row[row_key][field]))
48
+ return "\n".join(values)
50
49
 
51
50
  def get_row_value(self, row, key):
52
51
  row_key = self.config[key]["key"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: okdata-cli
3
- Version: 3.2.0
3
+ Version: 4.1.0
4
4
  Summary: CLI for services provided by Oslo Origo
5
5
  Home-page: https://github.com/oslokommune/okdata-cli/
6
6
  Author: Oslo Origo
@@ -19,7 +19,7 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: PrettyTable
21
21
  Requires-Dist: docopt
22
- Requires-Dist: okdata-sdk <4,>=3.1
22
+ Requires-Dist: okdata-sdk <4,>=3.1.1
23
23
  Requires-Dist: questionary <2.0.0,>=1.10.0
24
24
  Requires-Dist: requests
25
25
 
@@ -29,7 +29,7 @@ Okdata CLI provides a unified interface to data services for Oslo Origo teams.
29
29
 
30
30
  * [Install](doc/install.md)
31
31
  * [Configuration](doc/configuration.md)
32
- * [Public registers](doc/pubreg.md)
32
+ * [Public services](doc/pubs.md)
33
33
  * [Teams](doc/teams.md)
34
34
  * [Datasets](doc/datasets.md)
35
35
  * [Permissions](doc/permissions.md)
@@ -1,23 +1,23 @@
1
- okdata_cli-3.2.0-nspkg.pth,sha256=4nrP4RXuGOCDLZ0px0sO63KvnhR4W_t4MWel1CEdd2U,539
1
+ okdata_cli-4.1.0-nspkg.pth,sha256=4nrP4RXuGOCDLZ0px0sO63KvnhR4W_t4MWel1CEdd2U,539
2
2
  okdata/cli/__init__.py,sha256=72PLqW3-JGeKxQGusk3AX78ITwcn7DDawEMNLlsurz4,27
3
- okdata/cli/__main__.py,sha256=Q5T-QWTB9D349j1jiBtoMH0dB-jL_Qxai0J7oN_p_hM,2534
4
- okdata/cli/command.py,sha256=6XmpmN6VfUr5dTROeP3s5aqjOo6dCaf-WeaUfB44xs0,4285
3
+ okdata/cli/__main__.py,sha256=HpSOoNdhNn68GB9rkJZXDPx07RWxQjBkCEVIz9N_ydo,2608
4
+ okdata/cli/command.py,sha256=H65OJP72fRgip_vK_vJ8TDNan18OyO6WQNtj797mO3U,4281
5
5
  okdata/cli/io.py,sha256=cNm-h86fm3ez59A9rhWO0xnHBTIe-_Xj9BtcjKa34lg,730
6
- okdata/cli/output.py,sha256=_TC-iuKXBYgfY2BnMVcqKNZgrmXeb10mWychI1KtLzo,4802
6
+ okdata/cli/output.py,sha256=HAQKEwTj_GJXzIUqi4U3-VAt6CClRO2f3k6ZuDRjQ5A,4793
7
7
  okdata/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- okdata/cli/commands/permissions.py,sha256=52JPEoK7r3LCwHSWkMJk9qSosuOlQ-fiIS6Bt6VhFwI,4568
8
+ okdata/cli/commands/permissions.py,sha256=eLR9IGPi5OMZ7r46Bfl0SKS6WthmU2rSRcQh3n8mG9o,4476
9
9
  okdata/cli/commands/status.py,sha256=NkAuNEUWVumDsU-axFSOrX7AAJ-XV0fevsBbxpbl5CU,3998
10
- okdata/cli/commands/wizard.py,sha256=KhM-IVYzo6L0EPh9L9D9rpjyrEChImOaEjBzu7x8deA,341
10
+ okdata/cli/commands/validators.py,sha256=lkLo4UPmwXkKzEIFs0jucPVBV4jOPTZjzefpAvP1vdU,3882
11
+ okdata/cli/commands/wizard.py,sha256=FFNK6h50atWh0Tl7lOx1lSU0jC6QNRz0SqDuv5OcRew,541
11
12
  okdata/cli/commands/datasets/__init__.py,sha256=kS1uB6u_0VI1jm_TQjaCvTMqPFHnKSQITPUuPB_SY00,69
12
- okdata/cli/commands/datasets/datasets.py,sha256=Gfa_GxOJ3pIG9JtF4RhJI8W21SfJQ_BJOZLRBy1Dau4,13907
13
- okdata/cli/commands/datasets/questions.py,sha256=1VT76wEnVn_OFrDxfs3lbc0AUWsC1JbC5pTHXnjEm_k,5669
14
- okdata/cli/commands/datasets/validators.py,sha256=_PO3BcQW-mrz6BH6nkBjdvC5guSmoS7TUc_2inJKZoI,4461
15
- okdata/cli/commands/datasets/wizards.py,sha256=K3hRjvUD4nbrA2Fc536VsWRXmWawIozXX9mtlAHqHi4,3699
16
- okdata/cli/commands/pubreg/__init__.py,sha256=ag6UPDj1X2liovwazLL6hqvOZux2_syR1kce-FYw56A,89
17
- okdata/cli/commands/pubreg/client.py,sha256=n_vF3bhGKazDpUCu7i-KjH_8buBA_OLISDfN0SGyHK0,2392
18
- okdata/cli/commands/pubreg/pubreg.py,sha256=hJ5jiJGM-PWEtOA3-U4dDR6VVhS_oRuETO_4BJmFjqo,11255
19
- okdata/cli/commands/pubreg/questions.py,sha256=wl23CioGBl5nBLNfLIYqRjoFC1rXfhuUkHkvYrmGWi8,5459
20
- okdata/cli/commands/pubreg/wizards.py,sha256=_oEyJWQMaIfH0fIJs5KEggqtT1YimfwualeNGCqjzAU,3121
13
+ okdata/cli/commands/datasets/datasets.py,sha256=vt5MnhkLOAv-TFCcz4MkapBsDYwimXPV6TkoF5KFb3A,14045
14
+ okdata/cli/commands/datasets/questions.py,sha256=svesJS9MGwN3y2Utsy43HwWKPxe-K15neKt8A2eozqg,4004
15
+ okdata/cli/commands/datasets/wizards.py,sha256=X2xwiZpQhum9looqYbcuGgvSO1J_wAkaRNQf7NudxqU,3335
16
+ okdata/cli/commands/pubs/__init__.py,sha256=T105M_46YzyZ2Cici48QKNyjfJTIQJ1uyMFlo91rIZ4,81
17
+ okdata/cli/commands/pubs/client.py,sha256=dOabTkeZKPvHFbgwZC4SX4DyvnvEezpeSiLQ1EY1hlo,3223
18
+ okdata/cli/commands/pubs/pubs.py,sha256=WOeZvg8bUUJ7bXSvtfByF84IlH70jFF6-fe3tsvjhAY,12002
19
+ okdata/cli/commands/pubs/questions.py,sha256=0UwZ87Zcx5eAWLO3FI4aoLGvY3lQuLqEcYa6kUT8OLo,7020
20
+ okdata/cli/commands/pubs/wizards.py,sha256=fNhj-7G7ePEYVLrhmdXdNzRSdD-9BzVAcJxujuz7LwQ,3613
21
21
  okdata/cli/commands/teams/questions.py,sha256=UqfHK2bwl6retyYYC-IywG_39aRDC-WbKYpMIQ83gfE,2997
22
22
  okdata/cli/commands/teams/teams.py,sha256=ta4RRgRp-89CACh98nvbfbaxnE3EnloHVkNslBtgwKY,5633
23
23
  okdata/cli/commands/teams/util.py,sha256=c7U6jI7CN7MUyfsK6Z3AawL0SJJBlFar4FvXfsJQzSk,456
@@ -25,25 +25,25 @@ okdata/cli/commands/teams/wizards.py,sha256=bARELvUPdcbj5O7O1xwEL8Bcv7YNZYt2zyXq
25
25
  okdata/cli/data/output-format/datasets_config.json,sha256=rAvcNeBc0d53tWSAlWnt8IxvjNDWqm-b1sEgfk5IvF8,180
26
26
  okdata/cli/data/output-format/datasets_copy_file_config.json,sha256=wAKnX_B7d1keRGdIQBwsvF25oyD1aC2ZYLTDi_KPWzY,262
27
27
  okdata/cli/data/output-format/datasets_copy_file_config_2.json,sha256=7U0ka_IgSJv6vxQ6q7La8MPMy45Vwxb39_YSlQBMha0,206
28
- okdata/cli/data/output-format/datasets_dataset_config.json,sha256=inZaVE4GJK1EZm4O7DlbDuoXucuYm3bvVef4aTWVt-4,359
28
+ okdata/cli/data/output-format/datasets_dataset_config.json,sha256=J8uVCrU5ehHs3jYrqRm5HgJHnYmkWJaoZCcZnVWilpA,344
29
29
  okdata/cli/data/output-format/datasets_dataset_version_config.json,sha256=PW1PoW7PWkJj76RyfD5xEbYoeCf1yeC94s-ua5Z1GU8,345
30
30
  okdata/cli/data/output-format/datasets_dataset_version_edition_config.json,sha256=_UECCluFSMWwyIiZ1rBCS2LOnxiN1roZVEbQ71AW5Fo,328
31
31
  okdata/cli/data/output-format/datasets_dataset_version_edition_distributions_config.json,sha256=xTuQTNfBnnJFDF5aFLY5bBT1-qzd5cbceKqqxmF0NUU,119
32
32
  okdata/cli/data/output-format/datasets_dataset_versions_config.json,sha256=rqrhf-xK_RYkbP3dCZrn6m7CDVNn_Pg0GknGj2wDtHw,209
33
33
  okdata/cli/data/output-format/my_permissions_config.json,sha256=VPx95G_e6D6OJQJmXrS8ASKwUJP0uETqWam681edBQU,146
34
34
  okdata/cli/data/output-format/permissions_config.json,sha256=uPrYKhnEZEImsFZ4CpVdeOb8NrtdlnvfT4L0pvqiBuw,204
35
- okdata/cli/data/output-format/pubreg_audit_log_config.json,sha256=hXZV2-OUKElGiHTVQbslZqe_IeP1eGjktzhhAAcIbzg,301
36
- okdata/cli/data/output-format/pubreg_clients_config.json,sha256=aFbQIQldHfsRnI39SCE0cmm-3MDFq57r0ZsIzZ9HsHA,246
37
- okdata/cli/data/output-format/pubreg_multiple_client_keys_config.json,sha256=_mGvDgNeLBZZwos6JXVBESyHjYNIje8zKv08MKMVaug,201
38
- okdata/cli/data/output-format/pubreg_single_client_keys_config.json,sha256=LO78-h-9o_tfHSNQ_4dOfsxuNvoc1TxbOPTvseEZy6w,125
35
+ okdata/cli/data/output-format/pubs_audit_log_config.json,sha256=hXZV2-OUKElGiHTVQbslZqe_IeP1eGjktzhhAAcIbzg,301
36
+ okdata/cli/data/output-format/pubs_clients_config.json,sha256=aFbQIQldHfsRnI39SCE0cmm-3MDFq57r0ZsIzZ9HsHA,246
37
+ okdata/cli/data/output-format/pubs_multiple_client_keys_config.json,sha256=_mGvDgNeLBZZwos6JXVBESyHjYNIje8zKv08MKMVaug,201
38
+ okdata/cli/data/output-format/pubs_single_client_keys_config.json,sha256=LO78-h-9o_tfHSNQ_4dOfsxuNvoc1TxbOPTvseEZy6w,125
39
39
  okdata/cli/data/output-format/status_config.json,sha256=oq9uYZbPZrM2ksWrQDd9-VWO0Ea7jMe02TDgxg6XLEA,354
40
40
  okdata/cli/data/output-format/status_history_config.json,sha256=Gh-l8w9688P0hdp_DtJ9cxMc1bdv5DuNp5QBftOnb9M,721
41
41
  okdata/cli/data/output-format/team_members_config.json,sha256=CYzlVLU3f41kpxBbovXYDYRYOvhScfYU2yxtwHFMcuQ,183
42
42
  okdata/cli/data/output-format/teams_config.json,sha256=z49y_7m3b9W02guXXcSdlX9XDAaIj0rRBDcqU68m9i0,124
43
- okdata_cli-3.2.0.dist-info/LICENSE,sha256=9oNBrI2Aw9TCn-T0CamN4hpU6Dzm-IkFzX0573Q211Q,1077
44
- okdata_cli-3.2.0.dist-info/METADATA,sha256=W8lko1x9IKLxn6yXwOEd7xRB59GfmogErr_6x9Dp7YQ,1197
45
- okdata_cli-3.2.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
46
- okdata_cli-3.2.0.dist-info/entry_points.txt,sha256=OyY5saQTVah33LZ9ixM40rsMPgsOKErioZA8rtVjgKo,52
47
- okdata_cli-3.2.0.dist-info/namespace_packages.txt,sha256=Pdf-ZpWHLtLL295sDedsbAP3f6H189730mXrfVAVCcY,7
48
- okdata_cli-3.2.0.dist-info/top_level.txt,sha256=cS1IEDv6oxHgvQHrGSxFxjHTv5CNc9dLowH1vpCqF_k,11
49
- okdata_cli-3.2.0.dist-info/RECORD,,
43
+ okdata_cli-4.1.0.dist-info/LICENSE,sha256=9oNBrI2Aw9TCn-T0CamN4hpU6Dzm-IkFzX0573Q211Q,1077
44
+ okdata_cli-4.1.0.dist-info/METADATA,sha256=ymI274uuzhj-H3WCGCCxfUrzyWLpQSHYlnJxTBoVUT4,1196
45
+ okdata_cli-4.1.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
46
+ okdata_cli-4.1.0.dist-info/entry_points.txt,sha256=OyY5saQTVah33LZ9ixM40rsMPgsOKErioZA8rtVjgKo,52
47
+ okdata_cli-4.1.0.dist-info/namespace_packages.txt,sha256=Pdf-ZpWHLtLL295sDedsbAP3f6H189730mXrfVAVCcY,7
48
+ okdata_cli-4.1.0.dist-info/top_level.txt,sha256=cS1IEDv6oxHgvQHrGSxFxjHTv5CNc9dLowH1vpCqF_k,11
49
+ okdata_cli-4.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,3 +0,0 @@
1
- from okdata.cli.commands.pubreg.pubreg import PubregCommand
2
-
3
- __all__ = ["PubregCommand"]