forked from ietf-tools/datatracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodels.py
More file actions
98 lines (82 loc) · 3.18 KB
/
Copy pathmodels.py
File metadata and controls
98 lines (82 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Copyright The IETF Trust 2025, All Rights Reserved
import json
from functools import partial
from hashlib import sha384
from django.db import models, transaction
from django.utils import timezone
from .apps import get_blobdb
from .replication import replication_enabled
from .tasks import pybob_the_blob_replicator_task
class BlobQuerySet(models.QuerySet):
"""QuerySet customized for Blob management
Operations that bypass save() / delete() won't correctly notify watchers of changes
to the blob contents. Disallow them.
"""
def delete(self):
raise NotImplementedError("Only deleting individual Blobs is supported")
def bulk_create(self, *args, **kwargs):
raise NotImplementedError("Only creating individual Blobs is supported")
def update(self, *args, **kwargs):
# n.b., update_or_create() _does_ call save()
raise NotImplementedError("Updating BlobQuerySets is not supported")
def bulk_update(self, *args, **kwargs):
raise NotImplementedError("Updating Blobs in bulk is not supported")
class Blob(models.Model):
objects = BlobQuerySet.as_manager()
name = models.CharField(max_length=1024, help_text="Name of the blob")
bucket = models.CharField(
max_length=1024, help_text="Name of the bucket containing this blob"
)
modified = models.DateTimeField(
default=timezone.now, help_text="Last modification time of the blob"
)
content = models.BinaryField(help_text="Content of the blob")
checksum = models.CharField(
max_length=96, help_text="SHA-384 digest of the content", editable=False
)
mtime = models.DateTimeField(
default=None,
blank=True,
null=True,
help_text="mtime associated with the blob as a filesystem object",
)
content_type = models.CharField(
max_length=1024,
blank=True,
help_text="content-type header value for the blob contents",
)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["bucket", "name"], name="unique_name_per_bucket"
),
]
def save(self, **kwargs):
db = get_blobdb()
with transaction.atomic(using=db):
self.checksum = sha384(self.content, usedforsecurity=False).hexdigest()
super().save(**kwargs)
self._emit_blob_change_event(using=db)
def delete(self, **kwargs):
db = get_blobdb()
with transaction.atomic(using=db):
retval = super().delete(**kwargs)
self._emit_blob_change_event(using=db)
return retval
def _emit_blob_change_event(self, using=None):
if not replication_enabled(self.bucket):
return
# For now, fire a celery task we've arranged to guarantee in-order processing.
# Later becomes pushing an event onto a queue to a dedicated worker.
transaction.on_commit(
partial(
pybob_the_blob_replicator_task.delay,
json.dumps(
{
"name": self.name,
"bucket": self.bucket,
}
)
),
using=using,
)