add uri salt and fix api url namespaces

This commit is contained in:
Nick Sweeting 2024-08-17 21:56:23 -07:00
parent fba3995d86
commit 4d0bbfccfc
No known key found for this signature in database
6 changed files with 55 additions and 22 deletions

View file

@ -72,6 +72,10 @@ class ABID(NamedTuple):
subtype=suffix[18:20].upper(), subtype=suffix[18:20].upper(),
rand=suffix[20:26].upper(), rand=suffix[20:26].upper(),
) )
@property
def uri_salt(self) -> str:
return DEFAULT_ABID_URI_SALT
@property @property
def suffix(self): def suffix(self):

View file

@ -63,7 +63,7 @@ api = NinjaAPIWithIOCapture(
version='1.0.0', version='1.0.0',
csrf=False, csrf=False,
auth=API_AUTH_METHODS, auth=API_AUTH_METHODS,
urls_namespace="api", urls_namespace="api-1",
docs=Swagger(settings={"persistAuthorization": True}), docs=Swagger(settings={"persistAuthorization": True}),
# docs_decorator=login_required, # docs_decorator=login_required,
# renderer=ORJSONRenderer(), # renderer=ORJSONRenderer(),

View file

@ -33,7 +33,7 @@ class ArchiveResultSchema(Schema):
snapshot_tags: str snapshot_tags: str
extractor: str extractor: str
cmd_version: str cmd_version: Optional[str]
cmd: List[str] cmd: List[str]
pwd: str pwd: str
status: str status: str
@ -93,16 +93,16 @@ class ArchiveResultFilterSchema(FilterSchema):
created__lt: Optional[datetime] = Field(None, q='updated__lt') created__lt: Optional[datetime] = Field(None, q='updated__lt')
@router.get("/archiveresults", response=List[ArchiveResultSchema]) @router.get("/archiveresults", response=List[ArchiveResultSchema], url_name="get_archiveresult")
@paginate @paginate
def list_archiveresults(request, filters: ArchiveResultFilterSchema = Query(...)): def get_archiveresults(request, filters: ArchiveResultFilterSchema = Query(...)):
"""List all ArchiveResult entries matching these filters.""" """List all ArchiveResult entries matching these filters."""
qs = ArchiveResult.objects.all() qs = ArchiveResult.objects.all()
results = filters.filter(qs) results = filters.filter(qs)
return results return results
@router.get("/archiveresult/{archiveresult_id}", response=ArchiveResultSchema) @router.get("/archiveresult/{archiveresult_id}", response=ArchiveResultSchema, url_name="get_archiveresult")
def get_archiveresult(request, archiveresult_id: str): def get_archiveresult(request, archiveresult_id: str):
"""Get a specific ArchiveResult by abid, uuid, or pk.""" """Get a specific ArchiveResult by abid, uuid, or pk."""
return ArchiveResult.objects.get(Q(pk__icontains=archiveresult_id) | Q(abid__icontains=archiveresult_id) | Q(uuid__icontains=archiveresult_id)) return ArchiveResult.objects.get(Q(pk__icontains=archiveresult_id) | Q(abid__icontains=archiveresult_id) | Q(uuid__icontains=archiveresult_id))
@ -211,9 +211,9 @@ class SnapshotFilterSchema(FilterSchema):
@router.get("/snapshots", response=List[SnapshotSchema]) @router.get("/snapshots", response=List[SnapshotSchema], url_name="get_snapshots")
@paginate @paginate
def list_snapshots(request, filters: SnapshotFilterSchema = Query(...), with_archiveresults: bool=True): def get_snapshots(request, filters: SnapshotFilterSchema = Query(...), with_archiveresults: bool=True):
"""List all Snapshot entries matching these filters.""" """List all Snapshot entries matching these filters."""
request.with_archiveresults = with_archiveresults request.with_archiveresults = with_archiveresults
@ -221,7 +221,7 @@ def list_snapshots(request, filters: SnapshotFilterSchema = Query(...), with_arc
results = filters.filter(qs) results = filters.filter(qs)
return results return results
@router.get("/snapshot/{snapshot_id}", response=SnapshotSchema) @router.get("/snapshot/{snapshot_id}", response=SnapshotSchema, url_name="get_snapshot")
def get_snapshot(request, snapshot_id: str, with_archiveresults: bool=True): def get_snapshot(request, snapshot_id: str, with_archiveresults: bool=True):
"""Get a specific Snapshot by abid, uuid, or pk.""" """Get a specific Snapshot by abid, uuid, or pk."""
request.with_archiveresults = with_archiveresults request.with_archiveresults = with_archiveresults
@ -286,6 +286,6 @@ class TagSchema(Schema):
def resolve_created_by_id(obj): def resolve_created_by_id(obj):
return str(obj.created_by_id) return str(obj.created_by_id)
@router.get("/tags", response=List[TagSchema]) @router.get("/tags", response=List[TagSchema], url_name="get_tags")
def list_tags(request): def get_tags(request):
return Tag.objects.all() return Tag.objects.all()

View file

@ -168,28 +168,31 @@ def get_abid_info(self, obj):
return format_html( return format_html(
# URL Hash: <code style="font-size: 10px; user-select: all">{}</code><br/> # URL Hash: <code style="font-size: 10px; user-select: all">{}</code><br/>
''' '''
&nbsp; &nbsp; DB ID:&nbsp; &nbsp; &nbsp; <code style="font-size: 16px; user-select: all; border-radius: 8px; background-color: #fdd; padding: 1px 4px; border: 1px solid #aaa; margin-bottom: 14px;"><b>{}</b></code><br/> &nbsp; &nbsp; DB ID:&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <code style="font-size: 16px; user-select: all; border-radius: 8px; background-color: #fdd; padding: 1px 4px; border: 1px solid #aaa; margin-bottom: 8px; display: inline-block; vertical-align: top;"><b>{}</b></code><br/>
&nbsp; &nbsp; &nbsp; &nbsp;.id: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <code style="font-size: 10px; user-select: all">{}</code> &nbsp; &nbsp;<br/> &nbsp; &nbsp; &nbsp; &nbsp;.id: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <code style="font-size: 10px; user-select: all">{}</code> &nbsp; &nbsp;<br/>
&nbsp; &nbsp; &nbsp; &nbsp;.uuid: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all">{}</code> &nbsp; &nbsp;<br/> &nbsp; &nbsp; &nbsp; &nbsp;.uuid: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all">{}</code> &nbsp; &nbsp;<br/>
<br/> <br/>
<div style="opacity: 0.8"> <div style="opacity: 0.8">
&nbsp; &nbsp; ABID: &nbsp; &nbsp; &nbsp; <code style="font-size: 16px; user-select: all; border-radius: 8px; background-color: #fdd; padding: 1px 4px; border: 1px solid #aaa; margin-bottom: 14px;"><b>{}</b></code><br/> &nbsp; &nbsp; ABID: &nbsp; &nbsp; &nbsp; &nbsp; <small style="opacity: 0.5">{}_</small><code style="font-size: 16px; user-select: all; border-radius: 8px; background-color: #ddf; padding: 1px 4px; border: 1px solid #aaa; margin-bottom: 8px; display: inline-block; vertical-align: top;"><b>{}</b></code> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="{}" style="font-size: 1.5em; font-family: monospace;">/api/v1 GET JSON</a> &nbsp; &nbsp; <a href="{}" style="color: limegreen; font-size: 1.2em; vertical-align: 1px; font-family: monospace;">API DOCS</a><br/>
&nbsp; &nbsp; &nbsp; &nbsp; TS: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all"><b>{}</b></code> ({})<br/> &nbsp; &nbsp; &nbsp; &nbsp; TS: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all"><b>{}</b></code> &nbsp; &nbsp; &nbsp;&nbsp; ({})<br/>
&nbsp; &nbsp; &nbsp; &nbsp; URI: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> ({})<br/> &nbsp; &nbsp; &nbsp; &nbsp; URI: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; (<span style="display:inline-block; vertical-align: -4px; user-select: all; width: 230px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{}</span>)<br/>
&nbsp; &nbsp; &nbsp; &nbsp; SUBTYPE: &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> ({}) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SUBTYPE: &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> ({}) &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; RAND: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> ({})<br/><hr/> &nbsp; RAND: &nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> ({}) &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <small style="opacity: 0.8">as ULID: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all">{}</code></small><br/> &nbsp; SALT: &nbsp; <code style="font-size: 10px; user-select: all"><b style="display:inline-block; user-select: all; width: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{}</b></code>
&nbsp; &nbsp; &nbsp; &nbsp; <small style="opacity: 0.8">as UUID: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all">{}</code></small><br/><br/> <br/><hr/>
&nbsp; &nbsp; &nbsp; &nbsp; <small style="opacity: 0.8">.ulid: &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all">{}</code></small><br/>
&nbsp; &nbsp; &nbsp; &nbsp; <small style="opacity: 0.8">.uuid: &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all">{}</code></small><br/><br/>
</div> </div>
''', ''',
obj.pk, obj.pk,
obj.id, obj.id,
obj.uuid, obj.uuid,
obj.abid, *obj.abid.split('_', 1), obj.api_url, obj.api_docs_url,
obj.ABID.ts, obj.abid_values['ts'].isoformat() if isinstance(obj.abid_values['ts'], datetime) else obj.abid_values['ts'], obj.ABID.ts, obj.abid_values['ts'].isoformat() if isinstance(obj.abid_values['ts'], datetime) else obj.abid_values['ts'],
obj.ABID.uri, str(obj.abid_values['uri']), obj.ABID.uri, str(obj.abid_values['uri']),
obj.ABID.subtype, str(obj.abid_values['subtype']), obj.ABID.subtype, str(obj.abid_values['subtype']),
obj.ABID.rand, str(obj.abid_values['rand'])[-7:], obj.ABID.rand, str(obj.abid_values['rand'])[-7:],
obj.ABID.uri_salt,
obj.ABID.ulid, obj.ABID.ulid,
obj.ABID.uuid, obj.ABID.uuid,
) )

View file

@ -14,7 +14,7 @@ from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.text import slugify from django.utils.text import slugify
from django.core.cache import cache from django.core.cache import cache
from django.urls import reverse from django.urls import reverse, reverse_lazy
from django.db.models import Case, When, Value, IntegerField from django.db.models import Case, When, Value, IntegerField
from django.contrib.auth.models import User # noqa from django.contrib.auth.models import User # noqa
@ -103,6 +103,15 @@ class Tag(ABIDModel):
i = 1 if i is None else i+1 i = 1 if i is None else i+1
else: else:
return super().save(*args, **kwargs) return super().save(*args, **kwargs)
@property
def api_url(self) -> str:
# /api/v1/core/snapshot/{uulid}
return reverse_lazy('api-1:get_tag', args=[self.abid])
@property
def api_docs_url(self) -> str:
return f'/api/v1/docs#/Core%20Models/api_v1_core_get_tag'
class Snapshot(ABIDModel): class Snapshot(ABIDModel):
@ -167,6 +176,15 @@ class Snapshot(ABIDModel):
def icons(self) -> str: def icons(self) -> str:
return snapshot_icons(self) return snapshot_icons(self)
@property
def api_url(self) -> str:
# /api/v1/core/snapshot/{uulid}
return reverse_lazy('api-1:get_snapshot', args=[self.abid])
@property
def api_docs_url(self) -> str:
return f'/api/v1/docs#/Core%20Models/api_v1_core_get_snapshot'
@cached_property @cached_property
def extension(self) -> str: def extension(self) -> str:
@ -353,6 +371,14 @@ class ArchiveResult(ABIDModel):
def snapshot_dir(self): def snapshot_dir(self):
return Path(self.snapshot.link_dir) return Path(self.snapshot.link_dir)
@property
def api_url(self) -> str:
# /api/v1/core/archiveresult/{uulid}
return reverse_lazy('api-1:get_archiveresult', args=[self.abid])
@property
def api_docs_url(self) -> str:
return f'/api/v1/docs#/Core%20Models/api_v1_core_get_archiveresult'
@property @property
def extractor_module(self): def extractor_module(self):

View file

@ -38,7 +38,7 @@ urlpatterns = [
path('accounts/', include('django.contrib.auth.urls')), path('accounts/', include('django.contrib.auth.urls')),
path('admin/', archivebox_admin.urls), path('admin/', archivebox_admin.urls),
path("api/", include('api.urls')), path("api/", include('api.urls'), name='api'),
path('health/', HealthCheckView.as_view(), name='healthcheck'), path('health/', HealthCheckView.as_view(), name='healthcheck'),
path('error/', lambda *_: 1/0), path('error/', lambda *_: 1/0),