Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-27 07:41:45

0001 """Django models for swf-remote.
0002 
0003 Central to this repo: a generic tjai-style `Entry` table that holds any
0004 kind of customization data — alarm configs, alarm firings, engine run
0005 records, and whatever we add next (dashboards, annotations, ad-hoc notes).
0006 One flexible document-DB on top of swf-remote's existing Postgres.
0007 
0008 Shape follows tjai (tjai_app/models.py): content + kind + context +
0009 name + JSONField data + priority/status + timestamps + soft-delete,
0010 with `data.entry_id` as a non-unique human-readable slug (a single
0011 entry_id can appear across many rows — e.g. all events for one alarm
0012 share `data.entry_id = 'event_<alarm_name>'`).
0013 
0014 Archive policy: `status='archive'` entries are filtered out of live
0015 dashboard lists. Hard-delete via `deleted_at`.
0016 """
0017 from __future__ import annotations
0018 
0019 import time
0020 import uuid
0021 
0022 from django.db import models
0023 
0024 
0025 VALID_KINDS = (
0026     'alarm',       # alarm configuration
0027     'event',       # alarm firing (fire_time, clear_time, state in data)
0028     'engine_run',  # one swf-alarms engine tick, with aggregate counters
0029     'team',        # named recipient alias; Entry.name='@<teamname>',
0030                    # content holds whitespace-delimited emails.
0031     'memory',      # generic note, matches tjai
0032     'list',        # matches tjai
0033     'action',      # future: scheduled actions, matches tjai
0034 )
0035 
0036 VALID_STATUSES = ('active', 'done', 'blocked', 'failed')
0037 
0038 
0039 def _new_entry_id() -> str:
0040     """UUID4 default for Entry.id. Module-level so migrations can serialize it."""
0041     return str(uuid.uuid4())
0042 
0043 
0044 class EntryContext(models.Model):
0045     """Project/topic grouping for entries. Matches tjai Context model."""
0046     name = models.CharField(max_length=255, primary_key=True)
0047     title = models.CharField(max_length=255, blank=True, default='')
0048     description = models.TextField(blank=True, default='')
0049     timestamp_created = models.FloatField(default=time.time)
0050     timestamp_modified = models.FloatField(default=time.time)
0051     data = models.JSONField(default=dict, blank=True)
0052 
0053     class Meta:
0054         db_table = 'entry_context'
0055 
0056     def __str__(self):
0057         return self.name
0058 
0059 
0060 class Entry(models.Model):
0061     """Generic document-store row. See module docstring for the model."""
0062 
0063     id = models.CharField(max_length=36, primary_key=True,
0064                           default=_new_entry_id)
0065     # Human-readable title. swf-remote Entries don't follow tjai's
0066     # "first line of content is the title" convention — alarms, events,
0067     # engine runs need an explicit title. Optional; blank is fine for
0068     # kinds that don't care.
0069     title = models.CharField(max_length=255, blank=True, default='')
0070     content = models.TextField(blank=True, default='')
0071     kind = models.CharField(max_length=50)
0072     context = models.ForeignKey(EntryContext, on_delete=models.PROTECT,
0073                                 null=True, blank=True, related_name='entries')
0074     # `name` is the tjai @-style unique identifier within a context. Kept
0075     # for tjai symmetry; not used by alarms.
0076     name = models.CharField(max_length=255, null=True, blank=True)
0077     data = models.JSONField(null=True, blank=True)
0078     priority = models.IntegerField(null=True, blank=True)
0079     status = models.CharField(max_length=50, null=True, blank=True)
0080     # Explicit archive flag — filters out of live dashboard lists without
0081     # overloading `status`. Distinct from `deleted_at` (soft delete).
0082     archived = models.BooleanField(default=False)
0083     parent = models.ForeignKey('self', on_delete=models.SET_NULL,
0084                                null=True, blank=True, related_name='children')
0085     timestamp_created = models.FloatField(default=time.time)
0086     timestamp_modified = models.FloatField(default=time.time)
0087     deleted_at = models.FloatField(null=True, blank=True)
0088 
0089     class Meta:
0090         db_table = 'entry'
0091         constraints = [
0092             models.UniqueConstraint(
0093                 fields=['context', 'name'],
0094                 condition=models.Q(name__isnull=False),
0095                 name='uniq_context_name',
0096             ),
0097         ]
0098         indexes = [
0099             models.Index(fields=['kind', '-timestamp_created']),
0100             models.Index(fields=['context', 'kind', '-timestamp_created']),
0101             models.Index(fields=['archived']),
0102             models.Index(fields=['status']),
0103         ]
0104 
0105     def __str__(self):
0106         slug = (self.data or {}).get('entry_id') or self.name or self.id[:8]
0107         return f'{self.kind}:{slug}'
0108 
0109     @property
0110     def entry_id(self) -> str | None:
0111         """Human-readable slug from data.entry_id (non-unique by design)."""
0112         return (self.data or {}).get('entry_id')
0113 
0114 
0115 class EntryVersion(models.Model):
0116     """Immutable snapshot of an Entry's content + data at a point in time.
0117 
0118     Written by a pre_save signal on Entry whenever content or substantive
0119     data changes. Matches tjai's versioning pattern — UI can render a
0120     history table and load a prior version for re-editing.
0121     """
0122     entry = models.ForeignKey(Entry, on_delete=models.CASCADE,
0123                               related_name='versions')
0124     version_num = models.IntegerField()
0125     title = models.CharField(max_length=255, blank=True, default='')
0126     content = models.TextField(blank=True, default='')
0127     data = models.JSONField(null=True, blank=True)
0128     changed_by = models.CharField(max_length=100, default='unknown')
0129     timestamp = models.FloatField(default=time.time)
0130 
0131     class Meta:
0132         db_table = 'entry_version'
0133         constraints = [
0134             models.UniqueConstraint(fields=['entry', 'version_num'],
0135                                     name='uniq_entry_version_num'),
0136         ]
0137         indexes = [models.Index(fields=['entry', '-timestamp'])]