import logging import uuid from django.contrib.auth.models import AbstractUser from django.db import models logger = logging.getLogger(__name__) SITE_CHOICES = ( ("5HT2C", "5-HT2C"), ("5HT2A", "5-HT2A"), ("GABAB", "GABAB"), ("NMDA", "NMDA"), ) MECHANISM_CHOICES = ( ("AGONISM", "Agonism"), ("ANTAGONISM", "Antagomism"), ("MODULATION", "Modulation"), ) SOURCE_TYPE_CHOICES = ( ("PSITE", "Professional pharmaceutical data repository"), ("DWIKI", "Dedicated peer-reviewed community wiki"), ("CWIKI", "Peer-reviewed community wiki"), ("WIKI", "Private wiki"), ("DFORUM", "Dedicated community forum"), ("FORUM", "Community forum"), ) DOSAGE_UNIT_CHOICES = ( ("mg", "mg"), ("g", "g"), ("ug", "ug"), ) DOSAGE_TIMING_CHOICES = ( ("SECONDS", "Seconds"), ("MINUTES", "Minutes"), ("HOURS", "Hours"), ("DAYS", "Days :D"), ("WEEKS", "Weeks :O"), ("MONTHS", "Months :-|"), ("YEARS", "Years x_X"), ) SEI_TYPE_CHOICES = ( ("PHYSICAL", "Physical"), ("COGNITIVE", "Cognitive"), ("VISUAL", "Visual"), ("AUDITORY", "Auditory"), ("MULTISENSORY", "Multi-sensory"), ("TRANSPERSONAL", "Transpersonal"), ) class User(AbstractUser): # Stripe customer ID stripe_id = models.CharField(max_length=255, null=True, blank=True) customer_id = models.UUIDField(default=uuid.uuid4, null=True, blank=True) billing_provider_id = models.CharField(max_length=255, null=True, blank=True) email = models.EmailField(unique=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._original = self def get_notification_settings(self): return NotificationSettings.objects.get_or_create(user=self)[0] class NotificationSettings(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) ntfy_topic = models.CharField(max_length=255, null=True, blank=True) ntfy_url = models.CharField(max_length=255, null=True, blank=True) def __str__(self): return f"Notification settings for {self.user}" class Source(models.Model): """ A source of information. Any information. """ name = models.CharField(max_length=255, unique=True) type = models.CharField(max_length=255, choices=SOURCE_TYPE_CHOICES) # Base endpoint for automated crawler processes endpoint = models.CharField(max_length=1024, blank=True, null=True) # Score, affects ordering score = models.IntegerField(blank=True) class Entry(models.Model): """ A snippet of information located on a Source. Used to gather conflicting information and store it coherently. """ source = models.ForeignKey(Source) # Slug of the article on the Source slug = models.CharField(max_length=1024, null=True, blank=True) # Extra information can be added description = models.CharField(max_length=1024, null=True, blank=True) class Dosage(models.Model): """ Registers the correlation between dose and intensity. Linked to Entry to analyse conflicting records. """ entry = models.ForeignKey("core.Entry") # Unit of mass as drugs are diverse # Dosages varying between micrograms and grams unit = models.CharField(max_length=255, choices=DOSAGE_UNIT_CHOICES) # I can no longer say I am sober, but it is slight threshold = models.IntegerField() # Light light = models.IntegerField() # Average dose for a user common = models.IntegerField() # Strong intensity, many sober activities may become impossible strong = models.IntegerField() # Highest intensity heavy = models.IntegerField() class Timing(models.Model): """ Registers the time between administration to various experience levels. Linked to Entry to analyse conflicting records. """ entry = models.ForeignKey("core.Entry") # Unit of time as drugs are diverse # Half-lives varying between seconds and months unit = models.CharField( max_length=255, choices=DOSAGE_TIMING_CHOICES, default="HOURS" ) # It has just now begin, I can no longer say I am sober onset = models.IntegerField() # The intensity is accelerating comeup = models.IntegerField() # The maximum intensity has been reached # How long this state occurs peak = models.IntegerField() # How long it takes to get back to baseline offset = models.IntegerField(null=True, blank=True) total = models.IntegerField() class SEI(models.Model): """ Subjective Effect Index from Psychonaut Wiki. Registers a subjective effect in a category, allowing a description to be specified. """ # PHYSICAL, COGNITIVE, etc type = models.CharField( max_length=255, choices=SEI_TYPE_CHOICES, default="PHYSICAL" ) # WIP: consider euphoric, depressant, relaxant # Specify how description = models.CharField(max_length=4096, blank=True, null=True) class Effect(models.Model): """ Registers subjective effects for a drug. Linked to multiple subjective effect indexes all from the same entry. Linked to Entry to analyse conflicting records. """ entry = models.ForeignKey("core.Entry") # List of subjective effects, since they would likely be from the same entry subjective_effects = models.ManyToManyField(SEI) class Action(models.Model): """ Site action record for a drug. Registers a certain kind of action from a list of receptor sites with a given affinity. Linked to Entry to analyse conflicting records. """ entry = models.ForeignKey("core.Entry") # Site - like 5HT2A for LSD site = models.CharField(max_length=255, choices=SITE_CHOICES) # Usually agonist or antagonist mechanism = models.CharField(max_length=255, choices=MECHANISM_CHOICES) # Free integer for binding affinity affinity = models.IntegerField(blank=True) class Drug(models.Model): """ Model of a drug. Not open to interpretation. """ # Lysergic acid diethylamide, Phenibut name = models.CharField(max_length=255, unique=True) # Psychedelic, Sedative drug_class = models.CharField(max_length=255) # LSD common_name = models.CharField(max_length=1024, unique=True) # Factsheets, posts links = models.ManyToManyField(Entry) # Dosages, how much to take to get a certain effect dosages = models.ManyToManyField(Dosage) # Timings, how long to wait to reach maximum intensity (and others) timings = models.ManyToManyField(Timing) # Effects, what does it do on a subjective level? effects = models.ManyToManyField(Effect) # Actions, what does it do on an objective level? actions = models.ManyToManyField(Action) # class Perms(models.Model): # class Meta: # permissions = ( # ("bypass_hashing", "Can bypass field hashing"), # # ("bypass_blacklist", "Can bypass the blacklist"), # # ("bypass_encryption", "Can bypass field encryption"), # # ("bypass_obfuscation", "Can bypass field obfuscation"), # # ("bypass_delay", "Can bypass data delay"), # # ("bypass_randomisation", "Can bypass data randomisation"), # # ("post_irc", "Can post to IRC"), # ("post_discord", "Can post to Discord"), # ("query_search", "Can search with query strings"), # # ("use_insights", "Can use the Insights page"), # ("index_int", "Can use the internal index"), # ("index_meta", "Can use the meta index"), # ("restricted_sources", "Can access restricted sources"), # )