das-cli 1.2.16__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."""
@@ -316,6 +353,9 @@ class EntryManager:
316
353
  def __get_select_combobox_field_value(self, field, source: str) -> str:
317
354
  """Helper method to get select combobox field value."""
318
355
 
356
+ if not source:
357
+ return None
358
+
319
359
  attribute_id = -1
320
360
 
321
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.16
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=VzFU8CPoybU8VwOQ4maHoT0qS-_cBdQXzNDIJEHAiQk,22524
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.16.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
28
- das_cli-1.2.16.dist-info/METADATA,sha256=phODkhz41Byo1Y7TZUN15GFmZNgSDGQ_w3CcwPvFBMc,26210
29
- das_cli-1.2.16.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
30
- das_cli-1.2.16.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
31
- das_cli-1.2.16.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
32
- das_cli-1.2.16.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,,