das-cli 1.2.12__py3-none-any.whl → 1.2.19__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.
das/cli.py CHANGED
@@ -660,6 +660,78 @@ def get_entry(das_ctx, code=None, id=None):
660
660
  except Exception as e:
661
661
  click.secho(f"Error: {e}", fg="red")
662
662
 
663
+ @entry.command("logs")
664
+ @click.option('--id', 'entry_id', default=None, help='Entry ID (GUID)')
665
+ @click.option('--code', default=None, help='Entry code (resolved to ID if --id not provided)')
666
+ @click.option('--max-results', default=100, help='Maximum number of log items (default: 100)')
667
+ @click.option('--skip', default=0, help='Number of items to skip for pagination (default: 0)')
668
+ @click.option('--format', 'output_format', default='table', type=click.Choice(['table', 'json']), help='Output format (table or json)')
669
+ @pass_das_context
670
+ def entry_logs(das_ctx, entry_id, code, max_results, skip, output_format):
671
+ """Get change/audit logs for an entry by ID or code.
672
+
673
+ Examples:
674
+
675
+ \b
676
+ # By entry ID
677
+ das entry logs --id d7b99f36-5ccb-11f0-87f3-a84a63c8db73
678
+
679
+ \b
680
+ # By entry code with pagination
681
+ das entry logs --code ENT001 --max-results 50 --skip 0
682
+
683
+ \b
684
+ # JSON output
685
+ das entry logs --id d7b99f36-5ccb-11f0-87f3-a84a63c8db73 --format json
686
+ """
687
+ if not entry_id and not code:
688
+ raise click.UsageError("Please provide either --id or --code")
689
+ try:
690
+ das_ctx.get_client()
691
+ result = das_ctx.entry_manager.get_entry_logs(
692
+ entry_id=entry_id,
693
+ entry_code=code,
694
+ max_result_count=max_results,
695
+ skip_count=skip,
696
+ )
697
+ total_count = result.get("totalCount", 0)
698
+ items = result.get("items", [])
699
+ if output_format == "json":
700
+ click.echo(json.dumps(result, indent=2))
701
+ return
702
+ if not items:
703
+ click.secho("No log entries found.", fg="yellow")
704
+ return
705
+ click.secho(f"\nEntry logs ({total_count} total)", fg="blue")
706
+ headers = ["#", "Field", "From", "To", "Date/Time", "Modified by"]
707
+ table_data = []
708
+ for i, log in enumerate(items, 1):
709
+ # Truncate long valueFrom/valueTo for table display
710
+ v_from = (log.get("valueFrom") or "")[:40]
711
+ v_to = (log.get("valueTo") or "")[:40]
712
+ if (log.get("valueFrom") or "") and len(log.get("valueFrom", "")) > 40:
713
+ v_from += "..."
714
+ if (log.get("valueTo") or "") and len(log.get("valueTo", "")) > 40:
715
+ v_to += "..."
716
+ dt = log.get("logDateTime") or ""
717
+ if "T" in dt:
718
+ try:
719
+ date_part, time_part = dt.split("T")[0], dt.split("T")[1].split(".")[0]
720
+ dt = f"{date_part} {time_part}"
721
+ except Exception:
722
+ pass
723
+ table_data.append([
724
+ i,
725
+ (log.get("fieldName") or "")[:35],
726
+ v_from,
727
+ v_to,
728
+ dt,
729
+ (log.get("modifierUserName") or "")[:25],
730
+ ])
731
+ click.echo(format_table(table_data, headers))
732
+ except Exception as e:
733
+ click.secho(f"Error: {e}", fg="red")
734
+
663
735
  @entry.command("chown")
664
736
  @click.option('--user', 'user_name', required=True, help='New owner username')
665
737
  @click.option('--code', '-c', multiple=True, required=True, help='Entry code to transfer. Can be used multiple times.')
@@ -46,6 +46,43 @@ class EntryManager:
46
46
  raise ValueError("Entry ID is required")
47
47
 
48
48
  return self.get(id=entry_id)
49
+
50
+ def get_entry_logs(
51
+ self,
52
+ entry_id: str = None,
53
+ entry_code: str = None,
54
+ sorting: str = "",
55
+ max_result_count: int = 100,
56
+ skip_count: int = 0,
57
+ ):
58
+ """
59
+ Get change/audit logs for an entry by ID or code.
60
+
61
+ Args:
62
+ entry_id: Entry ID (GUID). Used directly if provided.
63
+ entry_code: Entry code. Resolves to ID via get(code=...) if entry_id is not provided.
64
+ sorting: Optional sort expression for the API.
65
+ max_result_count: Maximum number of log items to return (default 100).
66
+ skip_count: Number of items to skip for pagination (default 0).
67
+
68
+ Returns:
69
+ dict with 'totalCount' and 'items' (list of log entries with fieldName, valueFrom, valueTo, logDateTime, modifierUserName).
70
+ """
71
+ if not entry_id and not entry_code:
72
+ raise ValueError("Entry ID or code is required")
73
+ if entry_id:
74
+ id_to_use = entry_id
75
+ else:
76
+ entry = self.get(code=entry_code)
77
+ id_to_use = entry.get("ID") or entry.get("id")
78
+ if not id_to_use:
79
+ raise ValueError(f"Could not resolve entry ID for code: {entry_code}")
80
+ return self.entry_service.get_entry_logs(
81
+ id=id_to_use,
82
+ sorting=sorting,
83
+ max_result_count=max_result_count,
84
+ skip_count=skip_count,
85
+ )
49
86
 
50
87
  def get(self, id: str = None, code: str = None):
51
88
  """Get entry by id or code. The client parameter is not used but kept for backward compatibility."""
@@ -175,8 +212,6 @@ class EntryManager:
175
212
  new_entry[column_name] = self.__get_value(field, entry[field_name])
176
213
  elif column_name in entry:
177
214
  new_entry[column_name] = self.__get_value(field, entry[column_name])
178
- else:
179
- new_entry[column_name] = None
180
215
 
181
216
  return self.entry_service.create(attribute_id=attribute_id, entry=new_entry)
182
217
 
@@ -275,7 +310,7 @@ class EntryManager:
275
310
  for field in fields:
276
311
 
277
312
  field_name = field.get("displayName").lower()
278
- column_name = field.get("column").lower()
313
+ column_name = field.get("column").lower()
279
314
 
280
315
  if field.get('inputType') == GROUP_BOX_INPUT:
281
316
  # remove the column from the entry
@@ -285,8 +320,6 @@ class EntryManager:
285
320
  updated_entry[column_name] = self.__get_value(field, entry[field_name])
286
321
  elif column_name in entry:
287
322
  updated_entry[column_name] = self.__get_value(field, entry[column_name])
288
- else:
289
- updated_entry[column_name] = None
290
323
 
291
324
  return self.entry_service.update(attribute_id=attribute_id, entry=updated_entry)
292
325
 
@@ -303,8 +336,6 @@ class EntryManager:
303
336
  current_entry[column_name] = self.__get_value(field, entry[field_name])
304
337
  elif column_name in entry:
305
338
  current_entry[column_name] = self.__get_value(field, entry[column_name])
306
- else:
307
- current_entry[column_name] = None
308
339
 
309
340
  return current_entry
310
341
 
@@ -322,6 +353,9 @@ class EntryManager:
322
353
  def __get_select_combobox_field_value(self, field, source: str) -> str:
323
354
  """Helper method to get select combobox field value."""
324
355
 
356
+ if not source:
357
+ return None
358
+
325
359
  attribute_id = -1
326
360
 
327
361
  if field.get('column').isdigit():
das/services/entries.py CHANGED
@@ -156,6 +156,35 @@ class EntriesService():
156
156
  else:
157
157
  raise ValueError(response.get('error'))
158
158
 
159
+ def get_entry_logs(
160
+ self,
161
+ id: str,
162
+ sorting: str = "",
163
+ max_result_count: int = 100,
164
+ skip_count: int = 0,
165
+ ):
166
+ """Get change/audit logs for an entry by its ID."""
167
+ token = load_token()
168
+
169
+ if (token is None or token == ""):
170
+ raise ValueError("Authorization token is required")
171
+
172
+ headers = {
173
+ "Authorization": f"Bearer {token}"
174
+ }
175
+
176
+ url = (
177
+ f"{self.base_url}/GetEntryLogs"
178
+ f"?Id={id}&Sorting={sorting}&MaxResultCount={max_result_count}&SkipCount={skip_count}"
179
+ )
180
+
181
+ response = get_data(url, headers=headers)
182
+
183
+ if response.get('success') == True:
184
+ return response.get('result')
185
+ else:
186
+ raise ValueError(response.get('error'))
187
+
159
188
  def chown(self, new_user_id: int, entry_list_ids: list[str]):
160
189
  """Change the owner of a list of entries."""
161
190
  token = load_token()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: das-cli
3
- Version: 1.2.12
3
+ Version: 1.2.19
4
4
  Summary: DAS api client.
5
5
  Author: Royal Netherlands Institute for Sea Research
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  das/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  das/app.py,sha256=kKxN4Vn84SA5Ph3zY13avMG2vrUp-ffpdDkhwYR9Bho,1475
3
- das/cli.py,sha256=lh6RGqxACR4OOS7wrkhfD2yXli-Z7dsrch1_HNF05LM,51264
3
+ das/cli.py,sha256=fu484Q5vZmVLi720tFFvWobyLE34s022p-gRD-ArtA4,54228
4
4
  das/ai/plugins/dasai.py,sha256=1P-0q4ReAnmJxliGAPMxR1aij9RWKxyTIHJzWTwLZLo,2459
5
5
  das/ai/plugins/entries/entries_plugin.py,sha256=Dhv6PrguQj5mzxBW6DlCzkmwucszazLQfzwlp9EhIGk,608
6
6
  das/authentication/auth.py,sha256=DTtH66Ft6nuuMe7EYvrr3GqGVEGGxE7GmD2fO7vRv4s,1501
@@ -13,20 +13,20 @@ das/common/file_utils.py,sha256=Mb1uV9OAHle4zPSQFrythsU_8fzYV5grjgc1p9cmeA4,7129
13
13
  das/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  das/managers/digital_objects_manager.py,sha256=v7VAYfKoDpmWJGVgpVoSyk6hqGMiQJeOX5rgm65xE5U,3677
15
15
  das/managers/download_manager.py,sha256=bZuRX5yoKC_n00Tbjn_aRHgHLeq6SjI0TqDqgjttOQU,5431
16
- das/managers/entries_manager.py,sha256=VEu_lIN4YCsBr1QOnhzZ5I_DWs76oHebCBn9yFLNSkY,22754
16
+ das/managers/entries_manager.py,sha256=wnf4wqefi5WxY20y5KVB3C2iUXUku4XHpq_ySooI2gY,24038
17
17
  das/managers/search_manager.py,sha256=vXf0JmK5oW-xEGUdDnppfc1-6HdH1hfiZR7L2bCz9u0,4263
18
18
  das/services/attributes.py,sha256=78E9f1wNZYxG9Hg5HfX_h1CFmACaMjwD2Y6Ilb7PJGY,2616
19
19
  das/services/cache.py,sha256=g-vY51gqGV_1Vpza476PkMqGpuDNo1NbTwQWIIsvO0s,1932
20
20
  das/services/digital_objects.py,sha256=ww1KHVLNmm_ffzgqP4Jt4wCbHMVfhD2FJWahlSPFaes,4935
21
21
  das/services/downloads.py,sha256=cn2eoiKEDRcINlzoLgw6mpN3VVLBBiccdFyuCO7TB2I,3709
22
- das/services/entries.py,sha256=Dzvzx4wOljfumjBBg4sboXmgDTQf3FNbTQp-sl9hAn0,5755
22
+ das/services/entries.py,sha256=lNZY5OuMNtjkmoQjjtk9fADIoWzZmuq3ZWqK7RUUAP0,6589
23
23
  das/services/entry_fields.py,sha256=x2wUDkKNduj9pf4s56hRo0UW-eBhipkU9gFMEjFw5DA,1290
24
24
  das/services/hangfire.py,sha256=hidmVP9yb4znzBaJJRyKawYx7oYaBv5OVL-t0BhvN_A,818
25
25
  das/services/search.py,sha256=3X_KPb9fs024FhxoTr4j-xY5ymm5rvvzlekxuh8tLdg,1374
26
26
  das/services/users.py,sha256=iNijO2UPIEtcpPy8Tkemdxxym9rYLCUyckQHIQj68W0,795
27
- das_cli-1.2.12.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
28
- das_cli-1.2.12.dist-info/METADATA,sha256=ID1WVX6J2tyCuZXUyH1uGELD7nOO8j3mrFM1lAXORW0,26210
29
- das_cli-1.2.12.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
30
- das_cli-1.2.12.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
31
- das_cli-1.2.12.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
32
- das_cli-1.2.12.dist-info/RECORD,,
27
+ das_cli-1.2.19.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
28
+ das_cli-1.2.19.dist-info/METADATA,sha256=GMS6spfnE2UN4FU3zB6JfWbmrAYStq9voAOa5osWoD8,26210
29
+ das_cli-1.2.19.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
30
+ das_cli-1.2.19.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
31
+ das_cli-1.2.19.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
32
+ das_cli-1.2.19.dist-info/RECORD,,