Browse Source

add uri salt and fix api url namespaces

Nick Sweeting 1 year ago
parent
commit
4d0bbfccfc

+ 4 - 0
archivebox/abid_utils/abid.py

@@ -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):

+ 1 - 1
archivebox/api/v1_api.py

@@ -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(),

+ 9 - 9
archivebox/api/v1_core.py

@@ -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')
 
 
 
 
[email protected]("/archiveresults", response=List[ArchiveResultSchema])
[email protected]("/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
 
 
 
 
[email protected]("/archiveresult/{archiveresult_id}", response=ArchiveResultSchema)
[email protected]("/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):
 
 
 
 
 
 
[email protected]("/snapshots", response=List[SnapshotSchema])
[email protected]("/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
 
 
[email protected]("/snapshot/{snapshot_id}", response=SnapshotSchema)
[email protected]("/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)
 
 
[email protected]("/tags", response=List[TagSchema])
-def list_tags(request):
[email protected]("/tags", response=List[TagSchema], url_name="get_tags")
+def get_tags(request):
     return Tag.objects.all()
     return Tag.objects.all()

+ 13 - 10
archivebox/core/admin.py

@@ -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; &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;.uuid: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<code style="font-size: 10px; user-select: all">{}</code> &nbsp; &nbsp;<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; <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; &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; URI: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <code style="font-size: 10px; user-select: all"><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> &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> &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; &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; &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/>
+        &nbsp; RAND: &nbsp; <code style="font-size: 10px; user-select: all"><b>{}</b></code> ({}) &nbsp; &nbsp;
+        &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>
+        <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,
     )
     )

+ 27 - 1
archivebox/core/models.py

@@ -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):

+ 1 - 1
archivebox/core/urls.py

@@ -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),