Beispiel #1
0
 def test_with_validators(self):
     field = ArrayField(models.IntegerField(validators=[validators.MinValueValidator(1)]))
     field.clean([1, 2], None)
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean([0], None)
     self.assertEqual(cm.exception.code, 'item_invalid')
     self.assertEqual(cm.exception.messages[0], 'Item 0 in the array did not validate: Ensure this value is greater than or equal to 1.')
Beispiel #2
0
 def test_nested_array_mismatch(self):
     field = ArrayField(ArrayField(models.IntegerField()))
     field.clean([[1, 2], [3, 4]], None)
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean([[1, 2], [3, 4, 5]], None)
     self.assertEqual(cm.exception.code, 'nested_array_mismatch')
     self.assertEqual(cm.exception.messages[0], 'Nested arrays must have the same length.')
Beispiel #3
0
    def test_subclass_deconstruct(self):
        field = ArrayField(models.IntegerField())
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, 'django.contrib.postgres.fields.ArrayField')

        field = ArrayFieldSubclass()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, 'postgres_tests.models.ArrayFieldSubclass')
Beispiel #4
0
 def test_unbounded(self):
     field = ArrayField(models.IntegerField())
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean([1, None], None)
     self.assertEqual(cm.exception.code, 'item_invalid')
     self.assertEqual(
         cm.exception.message % cm.exception.params,
         'Item 1 in the array did not validate: This field cannot be null.'
     )
Beispiel #5
0
 def test_with_validators(self):
     field = ArrayField(models.IntegerField(validators=[validators.MinValueValidator(1)]))
     field.clean([1, 2], None)
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean([0], None)
     self.assertEqual(len(cm.exception.error_list), 1)
     exception = cm.exception.error_list[0]
     self.assertEqual(
         exception.message, "Item 0 in the array did not validate: Ensure this value is greater than or equal to 1."
     )
     self.assertEqual(exception.code, "item_invalid")
     self.assertEqual(exception.params, {"nth": 0, "value": 0, "limit_value": 1, "show_value": 0})
Beispiel #6
0
 def test_with_base_field_error_params(self):
     field = ArrayField(models.CharField(max_length=2))
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean(['abc'], None)
     self.assertEqual(len(cm.exception.error_list), 1)
     exception = cm.exception.error_list[0]
     self.assertEqual(
         exception.message,
         'Item 0 in the array did not validate: Ensure this value has at most 2 characters (it has 3).'
     )
     self.assertEqual(exception.code, 'item_invalid')
     self.assertEqual(exception.params, {'nth': 0, 'value': 'abc', 'limit_value': 2, 'show_value': 3})
Beispiel #7
0
 def test_with_base_field_error_params(self):
     field = ArrayField(models.CharField(max_length=2))
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean(["abc"], None)
     self.assertEqual(len(cm.exception.error_list), 1)
     exception = cm.exception.error_list[0]
     self.assertEqual(
         exception.message,
         "Item 0 in the array did not validate: Ensure this value has at most 2 characters (it has 3).",
     )
     self.assertEqual(exception.code, "item_invalid")
     self.assertEqual(exception.params, {"nth": 0, "value": "abc", "limit_value": 2, "show_value": 3})
Beispiel #8
0
 def test_deconstruct(self):
     field = ArrayField(models.IntegerField())
     name, path, args, kwargs = field.deconstruct()
     new = ArrayField(*args, **kwargs)
     self.assertEqual(type(new.base_field), type(field.base_field))
     self.assertIsNot(new.base_field, field.base_field)
class SummaryTransactionMonthView(models.Model):
    duh = models.UUIDField(primary_key=True,
                           help_text="Deterministic Unique Hash")
    action_date = models.DateField()
    fiscal_year = models.IntegerField()
    type = models.TextField()
    pulled_from = models.TextField()

    recipient_location_country_name = models.TextField()
    recipient_location_country_code = models.TextField()
    recipient_location_state_code = models.TextField()
    recipient_location_county_name = models.TextField()
    recipient_location_county_code = models.TextField()
    recipient_location_zip5 = models.TextField()
    recipient_location_congressional_code = models.TextField()
    recipient_location_city_name = models.TextField()

    pop_country_name = models.TextField()
    pop_country_code = models.TextField()
    pop_state_code = models.TextField()
    pop_county_name = models.TextField()
    pop_county_code = models.TextField()
    pop_zip5 = models.TextField()
    pop_congressional_code = models.TextField()
    pop_city_name = models.TextField()

    awarding_agency_id = models.IntegerField()
    funding_agency_id = models.IntegerField()
    awarding_toptier_agency_name = models.TextField()
    funding_toptier_agency_name = models.TextField()
    awarding_subtier_agency_name = models.TextField()
    funding_subtier_agency_name = models.TextField()
    awarding_toptier_agency_abbreviation = models.TextField()
    funding_toptier_agency_abbreviation = models.TextField()
    awarding_subtier_agency_abbreviation = models.TextField()
    funding_subtier_agency_abbreviation = models.TextField()

    recipient_hash = models.UUIDField()
    recipient_name = models.TextField()
    recipient_unique_id = models.TextField()
    parent_recipient_unique_id = models.TextField()
    business_categories = ArrayField(models.TextField(), default=list)
    cfda_number = models.TextField(blank=True, null=True)
    cfda_title = models.TextField(blank=True, null=True)
    product_or_service_code = models.TextField()
    product_or_service_description = models.TextField()
    naics_code = models.TextField(blank=True, null=True)
    naics_description = models.TextField(blank=True, null=True)

    total_obl_bin = models.TextField()
    type_of_contract_pricing = models.TextField()
    type_set_aside = models.TextField()
    extent_competed = models.TextField()

    generated_pragmatic_obligation = models.DecimalField(max_digits=23,
                                                         decimal_places=2,
                                                         null=True,
                                                         blank=True)
    federal_action_obligation = models.DecimalField(max_digits=23,
                                                    decimal_places=2,
                                                    blank=True,
                                                    null=True)
    original_loan_subsidy_cost = models.DecimalField(max_digits=23,
                                                     decimal_places=2,
                                                     null=True,
                                                     blank=True)
    face_value_loan_guarantee = models.DecimalField(max_digits=23,
                                                    decimal_places=2,
                                                    null=True,
                                                    blank=True)
    counts = models.IntegerField()

    class Meta:
        managed = False
        db_table = "summary_transaction_month_view"
Beispiel #10
0
class LeaderboardRank(SuperModel):
    """Define the Leaderboard Rank model."""

    profile = models.ForeignKey(
        'dashboard.Profile',
        on_delete=models.SET_NULL,
        null=True,
        related_name='leaderboard_ranks',
    )
    github_username = models.CharField(max_length=255)
    leaderboard = models.CharField(max_length=255, db_index=True)
    amount = models.FloatField(db_index=True)
    active = models.BooleanField(db_index=True)
    count = models.IntegerField(default=0)
    rank = models.IntegerField(default=0)
    product = models.CharField(max_length=255, db_index=True)
    tech_keywords = ArrayField(models.CharField(max_length=50),
                               blank=True,
                               default=list)

    objects = LeaderboardRankQuerySet.as_manager()

    class Meta:

        index_together = [
            ["leaderboard", "active"],
        ]

    def __str__(self):
        return f"{self.leaderboard}, {self.github_username}: {self.amount}"

    @property
    def github_url(self):
        return f"https://github.com/{self.github_username}"

    @property
    def is_not_user_based(self):
        profile_keys = [
            '_tokens', '_keywords', '_cities', '_countries', '_continents',
            '_kudos'
        ]
        return any(sub in self.leaderboard for sub in profile_keys)

    @property
    def is_a_kudos(self):
        return 'https://gitcoin.co/kudos/' == self.github_username[0:25]

    @property
    def at_ify_username(self):
        if not self.is_not_user_based:
            return f"@{self.github_username}"
        if self.is_a_kudos:
            pk = self.github_username.split('/')[4]
            from kudos.models import Token
            return Token.objects.get(pk=pk).humanized_name
        return self.github_username

    @property
    def avatar_url(self):
        if self.is_a_kudos:
            pk = self.github_username.split('/')[4]
            from kudos.models import Token
            return Token.objects.get(pk=pk).img_url
        key = self.github_username

        # these two types won't have images
        if self.is_not_user_based:
            key = 'None'

        return f"/dynamic/avatar/{key}"

    @property
    def url(self):
        if self.is_a_kudos:
            pk = self.github_username.split('/')[4]
            from kudos.models import Token
            return Token.objects.get(pk=pk).url
        ret_url = f"/profile/{self.github_username}"
        return ret_url
Beispiel #11
0
class EventReceiveUser(BaseModel):
    user_id = ArrayField(models.IntegerField())

    class Meta:
        db_table = 'event_receive_users'
Beispiel #12
0
class Doctor(models.Model):
    id = models.CharField(primary_key=True, unique=True, max_length=100)
    name = models.CharField(max_length=100, null=False)
    email = models.EmailField(max_length=100, null=False)
    medical_qual = models.CharField(choices=tuple(zip(MEDICAL_QUAL_CHOICES, MEDICAL_QUAL_CHOICES)), max_length=10)
    mci = models.IntegerField(null=False, unique=True)
    state_authority = models.CharField(max_length=100)
    contact_number = models.CharField(max_length=10, null=False)
    other_contact = models.CharField(max_length=10, null=True)
    time_pref = models.CharField(choices=tuple(zip(TIME_PREF_CHOICES, TIME_PREF_CHOICES)), max_length=10)
    language = ArrayField(models.CharField(max_length=10, blank=False))
    organisation_name = models.CharField(max_length=100)
    doctor_type = models.CharField(choices=tuple(zip(DOCTORS_TYPS, DOCTORS_TYPS)), max_length=10)
    duty_hours = models.CharField(choices=tuple(zip(DEDICATE_HOURS_CHOICE, DEDICATE_HOURS_CHOICE)), max_length=10)
    onboarding_status = models.CharField(choices=((ONBOARDING_SUCCEED, ONBOARDING_SUCCEED),
                                                  (ONBOARDING_FAIL, ONBOARDING_FAIL),
                                                  (ONBOARDING_REJECTED, ONBOARDING_REJECTED),
                                                  (ONBOARDING_UNQUALIFIED, ONBOARDING_UNQUALIFIED),
                                                  (ONBOARDING_QUEUE, ONBOARDING_QUEUE)), max_length=20)
    created_at = models.DateTimeField(auto_now_add=datetime.datetime.now())
    freshdesk_agent_created = models.BooleanField(default=False)
    comment = models.CharField(max_length=200)
    meta_status = models.CharField(max_length=100)
    doctor_data_already_downloaded = models.BooleanField(default=False)
    last_updated_staff = models.CharField(max_length=100, blank=True, null=True)

    def create(self, *args, **kwargs):
        if not self.id:
            self.id = uuid.uuid4().__str__()
        if not self.onboarding_status:
            self.onboarding_status = ONBOARDING_QUEUE
        if not self.created_at:
            self.created_at = datetime.datetime.now()
        if self.onboarding_status == ONBOARDING_SUCCEED:
            freshdesk_status = self.create_freshdesk_agent()
            if freshdesk_status == 201:
                self.freshdesk_agent_created = True
            # TODO: Log user id for which this fails
        return super(Doctor, self).create(*args, **kwargs)

    def save(self, *args, **kwargs):
        if not self.id:
            self.id = uuid.uuid4().__str__()
        if not self.onboarding_status:
            self.onboarding_status = ONBOARDING_QUEUE
        if not self.created_at:
            self.created_at = datetime.datetime.now()
        if self.onboarding_status == ONBOARDING_SUCCEED:
            freshdesk_status = self.create_freshdesk_agent()
            if freshdesk_status == 201:
                self.freshdesk_agent_created = True
            # TODO: Log user id for which this fails
        return super(Doctor, self).save(*args, **kwargs)

    def create_freshdesk_agent(self):
        req = {
            AgentAPIFields.email: self.email,
            AgentAPIFields.name: self.name,
            AgentAPIFields.mobile: str(self.contact_number),
            AgentAPIFields.ticket_scope: fd_const.TICKET_SCOPE,
            AgentAPIFields.language: fd_const.LANGUAGE
        }
        return create_agent(req)
Beispiel #13
0
class HDXExportRegion(models.Model):  # noqa
    PERIOD_CHOICES = (
        ('6hrs', 'Every 6 hours'),
        ('daily', 'Every day'),
        ('weekly', 'Every Sunday'),
        ('monthly', 'The 1st of every month'),
        ('disabled', 'Disabled'),
    )
    HOUR_CHOICES = zip(xrange(0, 24), xrange(0, 24))
    EXPORT_FORMAT_CHOICES = map(
        lambda name: (name, FORMAT_NAMES[name].description), FORMAT_NAMES)
    schedule_period = models.CharField(blank=False,
                                       max_length=10,
                                       default="disabled",
                                       choices=PERIOD_CHOICES)
    schedule_hour = models.IntegerField(blank=False,
                                        choices=HOUR_CHOICES,
                                        default=0)
    deleted = models.BooleanField(default=False)
    job = models.ForeignKey(Job,
                            null=True,
                            related_name='hdx_export_region_set')
    is_private = models.BooleanField(default=False)
    locations = ArrayField(models.CharField(blank=False, max_length=32),
                           null=True)
    license = models.CharField(max_length=32, null=True)
    subnational = models.BooleanField(default=True)
    extra_notes = models.TextField(null=True)

    class Meta:  # noqa
        db_table = 'hdx_export_regions'

    @property
    def delta(self):  # noqa
        if self.schedule_period == '6hrs':
            return timedelta(hours=6)

        if self.schedule_period == 'daily':
            return timedelta(days=1)

        if self.schedule_period == 'weekly':
            return timedelta(days=7)

        if self.schedule_period == 'monthly':
            return timedelta(days=31)

    @property
    def next_run(self):  # noqa
        now = timezone.now().replace(minute=0, second=0, microsecond=0)

        if self.schedule_period == '6hrs':
            delta = 6 - (self.schedule_hour + now.hour % 6)

            return now + timedelta(hours=delta)

        now = now.replace(hour=self.schedule_hour)

        if self.schedule_period == 'daily':
            anchor = now

            if timezone.now() < anchor:
                return anchor

            return anchor + timedelta(days=1)

        if self.schedule_period == 'weekly':
            # adjust so the week starts on Sunday
            anchor = now - timedelta((now.weekday() + 1) % 7)

            if timezone.now() < anchor:
                return anchor

            return anchor + timedelta(days=7)

        if self.schedule_period == 'monthly':
            (_, num_days) = calendar.monthrange(now.year, now.month)
            anchor = now.replace(day=1)

            if timezone.now() < anchor:
                return anchor

            return anchor + timedelta(days=num_days)

    @property
    def last_run(self):  # noqa
        last = self.job.runs.last()
        if last is not None:
            return last.finished_at

    @property
    def buffer_aoi(self):  # noqa
        return self.job.buffer_aoi

    @property
    def name(self):  # noqa
        return self.job.description

    @property
    def dataset_prefix(self):  # noqa
        return self.job.name

    @property
    def the_geom(self):  # noqa
        return json.loads(GEOSGeometry(self.job.the_geom).geojson)

    @property
    def feature_selection(self):  # noqa
        return self.job.feature_selection

    @property
    def export_formats(self):  # noqa
        return self.job.export_formats

    @property
    def datasets(self):  # noqa
        return map(
            lambda x: {
                'name':
                '{}_{}'.format(self.dataset_prefix, x),
                'url':
                '{}dataset/{}_{}'.format(HDX_URL_PREFIX, self.dataset_prefix, x
                                         ),
            }, self.job.feature_selection_object.themes)

    @property
    def runs(self):  # noqa
        return map(
            lambda run: {
                'elapsed_time':
                (run.finished_at or timezone.now()) - run.started_at,
                'run_at':
                run.started_at,
                'size':
                sum(map(lambda task: task.filesize_bytes or 0, run.tasks.all())
                    ),
                'status':
                run.status,
                'uid':
                run.uid,
            },
            self.job.runs.order_by('-created_at').all())

    @property
    def hdx_dataset(self):  # noqa
        """
        Initialize an HDXExportSet corresponding to this Model.
        """
        #       # TODO make distinction between GOESGeom/GeoJSON better
        return HDXExportSet(
            data_update_frequency=self.update_frequency,
            dataset_date=timezone.now(),
            dataset_prefix=self.dataset_prefix,
            extent=self.job.the_geom,
            extra_notes=self.extra_notes,
            feature_selection=self.job.feature_selection_object,
            is_private=self.is_private,
            license=self.license,
            locations=self.locations,
            name=self.name,
            subnational=self.subnational,
        )

    @property
    def update_frequency(self):
        """Update frequencies in HDX form."""
        if self.schedule_period == '6hrs':
            return 1

        if self.schedule_period == 'daily':
            return 1

        if self.schedule_period == 'weekly':
            return 7

        if self.schedule_period == 'monthly':
            return 30

        return 0

    def sync_to_hdx(self):  # noqa
        LOG.info("HDXExportRegion.sync_to_hdx called.")
        self.hdx_dataset.sync_datasets()
Beispiel #14
0
class MetaBusinessUnit(models.Model):
    """The object to link the different BusinessUnits."""
    name = models.TextField()

    dashboard_source = models.ForeignKey("inventory.Source",
                                         on_delete=models.SET_NULL,
                                         related_name="+",
                                         null=True,
                                         blank=True)
    dashboard_osx_app_bundle_id_list = ArrayField(models.TextField(),
                                                  default=list,
                                                  blank=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = MetaBusinessUnitManager()

    def __str__(self):
        return self.name

    class Meta:
        ordering = ('name', )

    def get_absolute_url(self):
        return reverse('inventory:mbu_machines', args=(self.id, ))

    def get_current_business_units(self):
        # !!! api enrollment business unit excluded !!!
        return BusinessUnit.objects.current().exclude(
            source__module='zentral.contrib.inventory').filter(
                meta_business_unit=self)

    def api_enrollment_business_units(self):
        return self.businessunit_set.filter(
            source__module='zentral.contrib.inventory').order_by('-id')

    def api_enrollment_enabled(self):
        return self.api_enrollment_business_units().count() > 0

    def create_enrollment_business_unit(self):
        reference = "MBU{}".format(self.id)
        b, created = BusinessUnit.objects.commit(
            {
                'source': {
                    'module': 'zentral.contrib.inventory',
                    'name': 'inventory'
                },
                'reference': reference,
                'name': reference
            },
            meta_business_unit=self)
        if created:
            b.set_meta_business_unit(self)
        return b

    def tags(self):
        tags = list(
            mbut.tag
            for mbut in self.metabusinessunittag_set.select_related('tag'))
        tags.sort(key=lambda t: (t.meta_business_unit is None, str(t).upper()))
        return tags

    def serialize(self):
        return {"name": self.name, "pk": self.pk}

    def can_be_deleted(self):
        for related_objects in find_all_related_objects(self):
            if len(related_objects.objects):
                if related_objects.name == "businessunit":
                    # OK to delete if all the business units can be deleted
                    for bu in related_objects.objects:
                        if not bu.can_be_deleted():
                            return False
                    continue
                else:
                    return False
        return True
Beispiel #15
0
class EnrollmentSecret(models.Model):
    secret = models.CharField(max_length=256, unique=True)
    meta_business_unit = models.ForeignKey(MetaBusinessUnit)
    tags = models.ManyToManyField(Tag, blank=True)
    serial_numbers = ArrayField(models.TextField(), blank=True, null=True)
    udids = ArrayField(models.TextField(), blank=True, null=True)
    quota = models.IntegerField(
        null=True,
        blank=True,
        validators=[MinValueValidator(1),
                    MaxValueValidator(200000)])
    request_count = models.IntegerField(default=0,
                                        validators=[MinValueValidator(0)])
    revoked_at = models.DateTimeField(null=True, blank=True)
    expired_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    objects = EnrollmentSecretManager()

    @property
    def is_revoked(self):
        return self.revoked_at is not None

    @property
    def is_expired(self):
        return bool(self.expired_at and self.expired_at <= timezone.now())

    @property
    def is_used_up(self):
        return bool(self.quota and self.request_count >= self.quota)

    def is_valid(self, serial_number=None, udid=None, meta_business_unit=None):
        err_msg = None
        if self.is_revoked:
            err_msg = "revoked"
        elif self.is_expired:
            err_msg = "expired"
        elif serial_number and self.serial_numbers and serial_number not in self.serial_numbers:
            err_msg = "serial number mismatch"
        elif udid and self.udids and udid not in self.udids:
            err_msg = "udid mismatch"
        elif meta_business_unit and meta_business_unit != self.meta_business_unit:
            err_msg = "business unit mismatch"
        elif self.is_used_up:
            err_msg = "quota used up"
        if err_msg:
            return False, err_msg
        else:
            return True, None

    def save(self, *args, **kwargs):
        if not self.pk:
            self.secret = get_random_string(kwargs.pop("secret_length", 64))
        super().save(*args, **kwargs)

    def serialize_for_event(self):
        d = {}
        for attr in ("pk", "quota", "request_count", "is_used_up",
                     "revoked_at", "is_revoked", "expired_at", "is_expired",
                     "created_at"):
            val = getattr(self, attr)
            if val is not None:
                d[attr] = val
        tags = [{"pk": t.pk, "name": t.name} for t in self.tags.all()]
        if tags:
            d["tags"] = tags
        if self.meta_business_unit:
            d["meta_business_unit"] = self.meta_business_unit.serialize()
        if self.serial_numbers:
            d["serial_numbers"] = self.serial_numbers
        if self.udids:
            d["udids"] = self.udids
        return {"enrollment_secret": d}

    def get_api_enrollment_business_unit(self):
        try:
            return self.meta_business_unit.api_enrollment_business_units()[0]
        except (AttributeError, IndexError):
            pass
Beispiel #16
0
class Protein(Authorable, StatusModel, TimeStampedModel):
    """ Protein class to store individual proteins, each with a unique AA sequence and name  """

    STATUS = Choices("pending", "approved", "hidden")

    MONOMER = "m"
    DIMER = "d"
    TANDEM_DIMER = "td"
    WEAK_DIMER = "wd"
    TETRAMER = "t"
    AGG_CHOICES = (
        (MONOMER, "Monomer"),
        (DIMER, "Dimer"),
        (TANDEM_DIMER, "Tandem dimer"),
        (WEAK_DIMER, "Weak dimer"),
        (TETRAMER, "Tetramer"),
    )

    BASIC = "b"
    PHOTOACTIVATABLE = "pa"
    PHOTOSWITCHABLE = "ps"
    PHOTOCONVERTIBLE = "pc"
    MULTIPHOTOCHROMIC = "mp"
    TIMER = "t"
    OTHER = "o"
    SWITCHING_CHOICES = (
        (BASIC, "Basic"),
        (PHOTOACTIVATABLE, "Photoactivatable"),
        (PHOTOSWITCHABLE, "Photoswitchable"),
        (PHOTOCONVERTIBLE, "Photoconvertible"),
        (MULTIPHOTOCHROMIC, "Multi-photochromic"),  # both convertible and switchable
        (OTHER, "Multistate"),
        (TIMER, "Timer"),
    )

    BILIRUBIN = "br"
    BILIVERDIN = "bv"
    FLAVIN = "fl"
    PHYCOCYANOBILIN = "pc"
    COFACTOR_CHOICES = (
        (BILIRUBIN, "Bilirubin"),
        (BILIVERDIN, "Biliverdin"),
        (FLAVIN, "Flavin"),
        (PHYCOCYANOBILIN, "Phycocyanobilin"),
    )

    # Attributes
    # uuid        = models.UUIDField(default=uuid_lib.uuid4, editable=False, unique=True)  # for API
    uuid = models.CharField(
        max_length=5,
        default=prot_uuid,
        editable=False,
        unique=True,
        db_index=True,
        verbose_name="FPbase ID",
    )
    name = models.CharField(
        max_length=128, help_text="Name of the fluorescent protein", db_index=True
    )
    slug = models.SlugField(
        max_length=64, unique=True, help_text="URL slug for the protein"
    )  # for generating urls
    base_name = models.CharField(max_length=128)  # easily searchable "family" name
    aliases = ArrayField(models.CharField(max_length=200), blank=True, null=True)
    chromophore = models.CharField(max_length=5, null=True, blank=True)
    seq_validated = models.BooleanField(
        default=False, help_text="Sequence has been validated by a moderator"
    )
    # seq must be nullable because of uniqueness contraints
    seq = SequenceField(
        unique=True,
        blank=True,
        null=True,
        verbose_name="Sequence",
        help_text="Amino acid sequence (IPG ID is preferred)",
    )
    seq_comment = models.CharField(
        max_length=512,
        blank=True,
        help_text="if necessary, comment on source of sequence",
    )

    pdb = ArrayField(
        models.CharField(max_length=4),
        blank=True,
        null=True,
        verbose_name="Protein DataBank IDs",
    )
    genbank = models.CharField(
        max_length=12,
        null=True,
        blank=True,
        unique=True,
        verbose_name="Genbank Accession",
        help_text="NCBI Genbank Accession",
    )
    uniprot = models.CharField(
        max_length=10,
        null=True,
        blank=True,
        unique=True,
        verbose_name="UniProtKB Accession",
        validators=[validate_uniprot],
    )
    ipg_id = models.CharField(
        max_length=12,
        null=True,
        blank=True,
        unique=True,
        verbose_name="IPG ID",
        help_text="Identical Protein Group ID at Pubmed",
    )  # identical protein group uid
    mw = models.FloatField(
        null=True, blank=True, help_text="Molecular Weight"
    )  # molecular weight
    agg = models.CharField(
        max_length=2,
        choices=AGG_CHOICES,
        blank=True,
        verbose_name="Oligomerization",
        help_text="Oligomerization tendency",
    )
    oser = models.FloatField(
        null=True, blank=True, help_text="OSER score"
    )  # molecular weight
    switch_type = models.CharField(
        max_length=2,
        choices=SWITCHING_CHOICES,
        blank=True,
        default="b",
        verbose_name="Switching Type",
        help_text="Photoswitching type (basic if none)",
    )
    blurb = models.TextField(
        max_length=512, blank=True, help_text="Brief descriptive blurb"
    )
    cofactor = models.CharField(
        max_length=2,
        choices=COFACTOR_CHOICES,
        blank=True,
        help_text="Required for fluorescence",
    )

    # Relations
    parent_organism = models.ForeignKey(
        "Organism",
        related_name="proteins",
        verbose_name="Parental organism",
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        help_text="Organism from which the protein was engineered",
    )
    primary_reference = models.ForeignKey(
        Reference,
        related_name="primary_proteins",
        verbose_name="Primary Reference",
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text="Preferably the publication that introduced the protein",
    )  # usually, the original paper that published the protein
    references = models.ManyToManyField(
        Reference, related_name="proteins", blank=True
    )  # all papers that reference the protein
    # FRET_partner = models.ManyToManyField('self', symmetrical=False, through='FRETpair', blank=True)
    default_state = models.ForeignKey(
        "State",
        related_name="default_for",
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )

    # __original_ipg_id = None

    # managers
    objects = ProteinManager()
    visible = QueryManager(~Q(status="hidden"))

    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     # store IPG_ID so that we know if it changes
    #     self.__original_ipg_id = self.ipg_id

    def mutations_from_root(self):
        try:
            root = self.lineage.get_root()
            if root.protein.seq and self.seq:
                muts = root.protein.seq.mutations_to(self.seq)
                return muts
        except ObjectDoesNotExist:
            return None

    @property
    def mless(self):
        return mless(self.name)

    @property
    def description(self):
        return util.long_blurb(self)

    @property
    def _base_name(self):
        '''return core name of protein, stripping prefixes like "m" or "Tag"'''
        return get_base_name(self.name)

    @property
    def versions(self):
        return Version.objects.get_for_object(self)

    def last_approved_version(self):
        if self.status == "approved":
            return self
        try:
            return (
                Version.objects.get_for_object(self)
                .filter(serialized_data__contains='"status": "approved"')
                .first()
            )
        except Exception:
            return None

    @property
    def additional_references(self):
        return self.references.exclude(id=self.primary_reference_id).order_by("-year")

    @property
    def em_css(self):
        if self.states.count() > 1:
            from collections import OrderedDict

            stops = OrderedDict({st.emhex: "" for st in self.states.all()})
            bgs = []
            stepsize = int(100 / (len(stops) + 1))
            sub = 0
            for i, _hex in enumerate(stops):
                if _hex == "#000":
                    sub = 18
                bgs.append("{} {}%".format(_hex, (i + 1) * stepsize - sub))
            return "linear-gradient(90deg, {})".format(", ".join(bgs))
        elif self.default_state:
            return self.default_state.emhex
        else:
            return "repeating-linear-gradient(-45deg,#333,#333 8px,#444 8px,#444 16px);"

    @property
    def em_svg(self):
        if self.states.count() > 1:
            stops = [st.emhex for st in self.states.all()]
            stepsize = int(100 / (len(stops) + 1))
            svgdef = "linear:"
            for i, color in enumerate(stops):
                perc = (i + 1) * stepsize
                if color == "#000":
                    perc *= 0.2
                svgdef += '<stop offset="{}%" style="stop-color:{};" />'.format(
                    perc, color
                )
            return svgdef
        if self.default_state:
            return self.default_state.emhex
        return "?"

    @property
    def color(self):
        try:
            return get_color_group(
                self.default_state.ex_max, self.default_state.em_max
            )[0]
        except Exception:
            return ""

    # Methods
    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("proteins:protein-detail", args=[self.slug])

    def has_default(self):
        return bool(self.default_state)

    def mutations_to(self, other, **kwargs):
        if isinstance(other, Protein):
            other = other.seq
        if not (self.seq and other):
            return None
        return self.seq.mutations_to(other, **kwargs)

    def mutations_from(self, other, **kwargs):
        if isinstance(other, Protein):
            other = other.seq
        if not (self.seq and other):
            return None
        return other.seq.mutations_to(self.seq, **kwargs)

    def has_spectra(self):
        for state in self.states.all():
            if state.has_spectra():
                return True
        return False

    def has_bleach_measurements(self):
        return self.states.filter(bleach_measurements__isnull=False).exists()

    def d3_spectra(self):
        spectra = []
        for state in self.states.all():
            spectra.extend(state.d3_dicts())
        return json.dumps(spectra)

    def spectra_img(self, fmt="svg", output=None, **kwargs):
        spectra = list(
            Spectrum.objects.filter(owner_state__protein=self).exclude(subtype="2p")
        )
        title = self.name if kwargs.pop("title", False) else None
        if kwargs.get("twitter", False):
            title = self.name
        info = ""
        if self.default_state:
            info += "Ex/Em λ: {}/{}".format(
                self.default_state.ex_max, self.default_state.em_max
            )
            info += "\nEC: {}   QY: {}".format(
                self.default_state.ext_coeff, self.default_state.qy
            )
        return spectra_fig(spectra, fmt, output, title=title, info=info, **kwargs)

    def set_default_state(self):
        # FIXME: should allow control of default states in form
        # if only 1 state, make it the default state
        if not self.default_state or self.default_state.is_dark:
            if self.states.count() == 1 and not self.states.first().is_dark:
                self.default_state = self.states.first()
            # otherwise use farthest red non-dark state
            elif self.states.count() > 1:
                self.default_state = (
                    self.states.exclude(is_dark=True).order_by("-em_max").first()
                )

    def clean(self):
        errors = {}
        # Don't allow basic switch_types to have more than one state.
        #        if self.switch_type == 'b' and self.states.count() > 1:
        #            errors.update({'switch_type': 'Basic (non photoconvertible) proteins '
        #                                          'cannot have more than one state.'})
        if self.pdb:
            self.pdb = list(set(self.pdb))
            for item in self.pdb:
                if (
                    Protein.objects.exclude(id=self.id)
                    .filter(pdb__contains=[item])
                    .exists()
                ):
                    p = Protein.objects.filter(pdb__contains=[item]).first()
                    errors.update(
                        {
                            "pdb": "PDB ID {} is already in use by protein {}".format(
                                item, p.name
                            )
                        }
                    )

        if errors:
            raise ValidationError(errors)

    def save(self, *args, **kwargs):

        # if the IPG ID has changed... refetch the sequence
        # if self.ipg_id != self.__original_ipg_id:
        #    s = fetch_ipg_sequence(uid=self.ipg_id)
        #    self.seq = s[1] if s else None

        self.slug = slugify(self.name)
        self.base_name = self._base_name
        self.set_default_state()

        super().save(*args, **kwargs)
        # self.__original_ipg_id = self.ipg_id

    # Meta
    class Meta:
        ordering = ["name"]

    def history(self, ignoreKeys=[]):
        from proteins.util.history import get_history

        return get_history(self, ignoreKeys)

    # ##################################
    # for algolia index

    def is_visible(self):
        return self.status != "hidden"

    def img_url(self):
        if self.has_spectra():
            return (
                "https://www.fpbase.org"
                + reverse("proteins:spectra-img", args=[self.slug])
                + ".png?xlabels=0&xlim=400,800"
            )
        else:
            return None

    def tags(self):
        tags = [self.get_switch_type_display(), self.get_agg_display(), self.color]
        return [i for i in tags if i]

    def date_published(self, norm=False):
        d = None
        if self.primary_reference:
            d = self.primary_reference.date
        if norm:
            return (d.year - 1992) / (datetime.datetime.now().year - 1992) if d else 0
        return datetime.datetime.combine(d, datetime.datetime.min.time()) if d else None

    def n_faves(self, norm=False):
        nf = (
            Favorite.objects.for_model(Protein).filter(target_object_id=self.id).count()
        )
        if norm:
            from collections import Counter

            mx = Counter(
                Favorite.objects.for_model(Protein).values_list(
                    "target_object_id", flat=True
                )
            ).most_common(1)
            if mx:
                mx = mx[0][1]
            else:
                mx = 1
            return nf / mx
        return nf

    def n_cols(self):
        return ProteinCollection.objects.filter(proteins=self.id).count()

    def ga_views(self, period="month", norm=False):
        from proteins.extrest.ga import cached_ga_popular

        hits = cached_ga_popular()[period]
        for slug, name, rating in hits:
            if slug == self.slug:
                return rating / max(list(zip(*hits))[2]) if norm else rating
        return 0

    def switchType(self):
        return self.get_switch_type_display()

    def _agg(self):
        return self.get_agg_display()

    def url(self):
        return self.get_absolute_url()

    def ex(self):
        if not self.states.exists():
            return None
        ex = [s.ex_max for s in self.states.all()]
        return ex[0] if len(ex) == 1 else ex

    def em(self):
        if not self.states.exists():
            return None
        em = [s.em_max for s in self.states.all()]
        return em[0] if len(em) == 1 else em

    def pka(self):
        if not self.states.exists():
            return None
        n = [s.pka for s in self.states.all()]
        return n[0] if len(n) == 1 else n

    def ec(self):
        if not self.states.exists():
            return None
        n = [s.ext_coeff for s in self.states.all()]
        return n[0] if len(n) == 1 else n

    def qy(self):
        if not self.states.exists():
            return None
        n = [s.qy for s in self.states.all()]
        return n[0] if len(n) == 1 else n

    def rank(self):
        # max rank is 1
        return (
            0.5 * self.date_published(norm=True)
            + 0.6 * self.ga_views(norm=True)
            + 1.0 * self.n_faves(norm=True)
        ) / 2.5

    def local_brightness(self):
        if self.states.exists():
            return max([s.local_brightness for s in self.states.all()])

    def first_author(self):
        if self.primary_reference and self.primary_reference.first_author:
            return self.primary_reference.first_author.family
Beispiel #17
0
class Request(models.Model):
    district = models.CharField(max_length=15,
                                choices=districts,
                                verbose_name='District - ജില്ല')
    location = models.CharField(max_length=500,
                                verbose_name='Location - സ്ഥലം')
    requestee = models.CharField(max_length=100,
                                 verbose_name='Requestee - അപേക്ഷകന്‍റെ പേര്')

    phone_number_regex = RegexValidator(
        regex='^((\+91|91|0)[\- ]{0,1})?[456789]\d{9}$',
        message=
        'Please Enter 10/11 digit mobile number or landline as 0<std code><phone number>',
        code='invalid_mobile')
    requestee_phone = models.CharField(
        max_length=14,
        verbose_name='Requestee Phone - അപേക്ഷകന്‍റെ ഫോണ്‍ നമ്പര്‍',
        validators=[phone_number_regex])

    latlng = models.CharField(
        max_length=100,
        verbose_name='GPS Coordinates - GPS നിർദ്ദേശാങ്കങ്ങൾ ',
        blank=True)
    latlng_accuracy = models.CharField(
        max_length=100, verbose_name='GPS Accuracy - GPS കൃത്യത ', blank=True)
    #  If it is enabled no need to consider lat and lng
    is_request_for_others = models.BooleanField(
        verbose_name=
        'Requesting for others - മറ്റൊരാൾക്ക് വേണ്ടി അപേക്ഷിക്കുന്നു  ',
        default=False,
        help_text="If it is enabled, no need to consider lat and lng")

    needwater = models.BooleanField(verbose_name='Water - വെള്ളം')
    needfood = models.BooleanField(verbose_name='Food - ഭക്ഷണം')
    needcloth = models.BooleanField(verbose_name='Clothing - വസ്ത്രം')
    needmed = models.BooleanField(verbose_name='Medicine - മരുന്നുകള്‍')
    needtoilet = models.BooleanField(
        verbose_name='Toiletries - ശുചീകരണ സാമഗ്രികള്‍ ')
    needkit_util = models.BooleanField(
        verbose_name='Kitchen utensil - അടുക്കള സാമഗ്രികള്‍')
    needrescue = models.BooleanField(
        verbose_name='Need rescue - രക്ഷാപ്രവർത്തനം ആവശ്യമുണ്ട്')

    detailwater = models.CharField(
        max_length=250,
        verbose_name=
        'Details for required water - ആവശ്യമായ വെള്ളത്തിന്‍റെ വിവരങ്ങള്‍',
        blank=True)
    detailfood = models.CharField(
        max_length=250,
        verbose_name=
        'Details for required food - ആവശ്യമായ ഭക്ഷണത്തിന്‍റെ വിവരങ്ങള്‍',
        blank=True)
    detailcloth = models.CharField(
        max_length=250,
        verbose_name=
        'Details for required clothing - ആവശ്യമായ വസ്ത്രത്തിന്‍റെ വിവരങ്ങള്‍',
        blank=True)
    detailmed = models.CharField(
        max_length=250,
        verbose_name=
        'Details for required medicine - ആവശ്യമായ മരുന്നിന്‍റെ  വിവരങ്ങള്‍',
        blank=True)
    detailtoilet = models.CharField(
        max_length=250,
        verbose_name=
        'Details for required toiletries - ആവശ്യമായ  ശുചീകരണ സാമഗ്രികള്‍',
        blank=True)
    detailkit_util = models.CharField(
        max_length=250,
        verbose_name=
        'Details for required kitchen utensil - ആവശ്യമായ അടുക്കള സാമഗ്രികള്‍',
        blank=True)
    detailrescue = models.CharField(
        max_length=250,
        verbose_name='Details for rescue action - രക്ഷാപ്രവർത്തനം വിവരങ്ങള്',
        blank=True)

    needothers = models.CharField(
        max_length=500,
        verbose_name="Other needs - മറ്റു ആവശ്യങ്ങള്‍",
        blank=True)
    status = models.CharField(max_length=10,
                              choices=status_types,
                              default='new')
    supply_details = models.CharField(max_length=100, blank=True)
    additional_phone_numbers = ArrayField(
        models.CharField(max_length=200),
        blank=True,
        default=list,
        verbose_name=
        'Additional phone numbers separated by space - അധിക ഫോൺ നമ്പർ സ്പെയ്സ് കൊണ്ട് വേർതിരിച്ചിരിക്കുന്നു'
    )
    dateadded = models.DateTimeField(auto_now_add=True)

    def summarise(self):
        out = ""
        if (self.needwater):
            out += "Water Requirements :\n {}".format(self.detailwater)
        if (self.needfood):
            out += "\nFood Requirements :\n {}".format(self.detailfood)
        if (self.needcloth):
            out += "\nCloth Requirements :\n {}".format(self.detailcloth)
        if (self.needmed):
            out += "\nMedicine Requirements :\n {}".format(self.detailmed)
        if (self.needtoilet):
            out += "\nToilet Requirements :\n {}".format(self.detailtoilet)
        if (self.needkit_util):
            out += "\nKit Requirements :\n {}".format(self.detailkit_util)
        if (len(self.needothers.strip()) != 0):
            out += "\nOther Needs :\n {}".format(self.needothers)
        if self.additional_phone_numbers:
            out += "\nAdditional phone numbers :\n {}".format("\n".join(
                self.additional_phone_numbers))
        return out

    class Meta:
        verbose_name = 'Rescue: Request'
        verbose_name_plural = 'Rescue:Requests'

    def __str__(self):
        return self.get_district_display() + ' ' + self.location

    def save(self, *args, **kwargs):
        if self.additional_phone_numbers:
            self.additional_phone_numbers = [
                item.strip()
                for item in self.additional_phone_numbers[0].split(' ')
                if item is not ''
                and re.match("^((\+91|91|0)[\- ]{0,1})?[456789]\d{9}$",
                             item) is not None
            ]
        super(Request, self).save(*args, **kwargs)
Beispiel #18
0
class ToDoItem(models.Model):
    course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True)
    ec = models.ForeignKey(Extracurricular,
                           on_delete=models.SET_NULL,
                           null=True,
                           verbose_name='Extracurriculars')
    title = models.CharField(max_length=100)
    description = models.CharField(max_length=600, blank=True, default="")
    duedate = models.DateTimeField(default=django.utils.timezone.now,
                                   blank=True)
    location = models.CharField(max_length=50, blank=True)
    completed = models.BooleanField(default=False)
    progress = models.IntegerField(
        default=0,
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        verbose_name="Progress")

    # recurrence freq choices
    NEVER = 'NEVER'
    DAILY = 'DAILY'
    WEEKLY = 'WEEKLY'
    MONTHLY = 'MONTHLY'
    YEARLY = 'YEARLY'
    FREQ_CHOICES = [
        (NEVER, 'Never'),
        (DAILY, 'Daily'),
        (WEEKLY, 'Weekly'),
        (MONTHLY, 'Monthly'),
        (YEARLY, 'Yearly'),
    ]
    recur_freq = models.CharField(
        max_length=7,
        choices=FREQ_CHOICES,
        default=NEVER,
    )
    # customize day of week
    # every other day
    # every other week
    end_recur_date = models.DateTimeField(default=django.utils.timezone.now,
                                          blank=True)
    # end repeat date and time
    # end after a specific day
    # never
    # end after # occurrences

    # priority choices
    HIGH = 'HI'
    MEDIUM = 'MD'
    LOW = 'LO'
    PRIORITY_CHOICES = [(LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High')]
    priority = models.CharField(
        max_length=2,
        choices=PRIORITY_CHOICES,
        default=LOW,
    )

    # category choices
    CATEGORIES = [('NN', 'None'), ('AC', 'Academics'),
                  ('EC', 'Extracurriculars'), ('JB', 'Job'), ('SC', 'Social'),
                  ('PS', 'Personal'), ('OT', 'Other')]
    category = models.CharField(
        max_length=2,
        choices=CATEGORIES,
        default='NN',
        verbose_name='Category',
    )

    has_title_changed = models.BooleanField(default=False)
    has_description_changed = models.BooleanField(default=False)
    has_duedate_changed = models.BooleanField(default=False)
    has_location_changed = models.BooleanField(default=False)
    has_recur_freq_changed = models.BooleanField(default=False)
    has_end_recur_date_changed = models.BooleanField(default=False)
    has_category_changed = models.BooleanField(default=False)
    has_priority_changed = models.BooleanField(default=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)

    # array storing id of future events associated with current object
    future_events = ArrayField(models.IntegerField(default=0),
                               default=list,
                               null=True)
    number_of_subtasks = models.IntegerField(default=0)

    # https://stackoverflow.com/questions/36617145/django-arrayfield-null-true-migration-with-postgresql
    tracker = FieldTracker()  # track changes to fields

    def __str__(self):
        return self.title + " " + self.duedate.strftime('%Y-%m-%d')

    def is_past_due(self):
        now = django.utils.timezone.now()
        return now > self.duedate

    def is_today_duedate(self):
        now = django.utils.timezone.now()
        due = self.duedate
        is_same = (now.day == due.day and now.month == due.month
                   and now.year == due.year)
        return is_same
Beispiel #19
0
 def test_deconstruct_args(self):
     field = ArrayField(models.CharField(max_length=20))
     name, path, args, kwargs = field.deconstruct()
     new = ArrayField(*args, **kwargs)
     self.assertEqual(new.base_field.max_length, field.base_field.max_length)
Beispiel #20
0
class Job(TimeStampedModelMixin):
    """
    Model for a Job.
    """
    id = models.AutoField(primary_key=True, editable=False)
    uid = models.UUIDField(unique=True,
                           default=uuid.uuid4,
                           editable=False,
                           db_index=True)
    user = models.ForeignKey(User, related_name='owner')
    name = models.CharField(max_length=100, db_index=True)
    description = models.CharField(max_length=1000, db_index=True)
    event = models.CharField(max_length=100,
                             db_index=True,
                             default='',
                             blank=True)
    export_formats = ArrayField(models.CharField(max_length=10), default=list)
    config = models.ForeignKey(ExportConfig, related_name='config', null=True)
    published = models.BooleanField(default=False,
                                    db_index=True)  # publish export
    feature_save = models.BooleanField(
        default=False, db_index=True)  # save feature selections
    feature_pub = models.BooleanField(
        default=False, db_index=True)  # publish feature selections
    the_geom = models.GeometryField(verbose_name='Extent for export',
                                    srid=4326,
                                    default='')
    objects = models.GeoManager()
    feature_selection = models.TextField(blank=True)
    buffer_aoi = models.BooleanField(default=False)

    class Meta:  # pragma: no cover
        managed = True
        db_table = 'jobs'

    def save(self, *args, **kwargs):
        super(Job, self).save(*args, **kwargs)

    def __str__(self):
        return '{0}'.format(self.name)

    @property
    def feature_selection_object(self):
        """
        a valid FeatureSelection object based off the feature_selection column.
        """
        fs = FeatureSelection(self.feature_selection)
        # assert fs.valid, 'Feature selection is invalid'
        return fs

    @property
    def tag_dict(self, ):
        """
        Return the unique set of Tag keys from this export
        with their associated geometry types.

        Used by Job.categorised_tags (below) to categorize tags
        according to their geometry types.
        """
        # get the unique keys from the tags for this export
        uniq_keys = list(self.tags.values('key').distinct('key'))
        tag_dict = {}  # mapping of tags to geom_types
        for entry in uniq_keys:
            key = entry['key']
            tag_dict['key'] = key
            geom_types = list(self.tags.filter(key=key).values('geom_types'))
            geom_type_list = []
            for geom_type in geom_types:
                geom_list = geom_type['geom_types']
                geom_type_list.extend([i for i in geom_list])
            tag_dict[key] = list(
                set(geom_type_list))  # get unique values for geomtypes
        return tag_dict

    @property
    def filters(self, ):
        """
        Return key=value pairs for each tag in this export.

        Used in utils.overpass.filter to filter the export.
        """
        filters = []
        for tag in self.tags.all():
            kv = '{0}={1}'.format(tag.key, tag.value)
            filters.append(kv)
        return filters

    @property
    def categorised_tags(self, ):
        """
        Return tags mapped according to their geometry types.
        """
        points = []
        lines = []
        polygons = []
        for tag in self.tag_dict:
            for geom in self.tag_dict[tag]:
                if geom == 'point':
                    points.append(tag)
                if geom == 'line':
                    lines.append(tag)
                if geom == 'polygon':
                    polygons.append(tag)
        return {
            'points': sorted(points),
            'lines': sorted(lines),
            'polygons': sorted(polygons)
        }
Beispiel #21
0
class OCPAzureCostLineItemDailySummary(models.Model):
    """A summarized view of OCP on Azure cost."""
    class Meta:
        """Meta for OCPAzureCostLineItemDailySummary."""

        db_table = "reporting_ocpazurecostlineitem_daily_summary"

        indexes = [
            models.Index(fields=["usage_start"],
                         name="ocpazure_usage_start_idx"),
            models.Index(fields=["namespace"], name="ocpazure_namespace_idx"),
            models.Index(fields=["node"],
                         name="ocpazure_node_idx",
                         opclasses=["varchar_pattern_ops"]),
            models.Index(fields=["resource_id"], name="ocpazure_resource_idx"),
            GinIndex(fields=["tags"], name="ocpazure_tags_idx"),
            models.Index(fields=["service_name"],
                         name="ocpazure_service_name_idx"),
            models.Index(fields=["instance_type"],
                         name="ocpazure_instance_type_idx"),
            # A GIN functional index named "ix_ocpazure_service_name_ilike" was created manually
            # via RunSQL migration operation
            # Function: (upper(service_name) gin_trgm_ops)
        ]

    # OCP Fields
    report_period = models.ForeignKey("OCPUsageReportPeriod",
                                      on_delete=models.CASCADE,
                                      null=True)

    cluster_id = models.CharField(max_length=50, null=True)

    cluster_alias = models.CharField(max_length=256, null=True)

    # Kubernetes objects by convention have a max name length of 253 chars
    namespace = ArrayField(models.CharField(max_length=253, null=False))

    pod = ArrayField(models.CharField(max_length=253, null=False))

    node = models.CharField(max_length=253, null=True)

    resource_id = models.CharField(max_length=253, null=True)

    usage_start = models.DateField(null=False)

    usage_end = models.DateField(null=False)

    # Azure Fields
    cost_entry_bill = models.ForeignKey("AzureCostEntryBill",
                                        on_delete=models.CASCADE)

    subscription_guid = models.TextField(null=False)

    instance_type = models.TextField(null=True)

    service_name = models.TextField(null=True)

    resource_location = models.TextField(null=True)

    tags = JSONField(null=True)

    usage_quantity = models.DecimalField(max_digits=24,
                                         decimal_places=9,
                                         null=True)

    # Cost breakdown can be done by cluster, node, project, and pod.
    # Cluster and node cost can be determined by summing the Azure pretax_cost
    # with a GROUP BY cluster/node.
    # Project cost is a summation of pod costs with a GROUP BY project
    # The cost of un-utilized resources = sum(pretax_cost) - sum(project_cost)
    pretax_cost = models.DecimalField(max_digits=17,
                                      decimal_places=9,
                                      null=True)

    markup_cost = models.DecimalField(max_digits=17,
                                      decimal_places=9,
                                      null=True)

    offer_id = models.PositiveIntegerField(null=True)

    currency = models.TextField(null=True)

    unit_of_measure = models.TextField(null=True)

    # This is a count of the number of projects that share an AWS resource
    # It is used to divide cost evenly among projects
    shared_projects = models.IntegerField(null=False, default=1)

    # A JSON dictionary of the project cost, keyed by project/namespace name
    # See comment on pretax_cost for project cost explanation
    project_costs = JSONField(null=True)

    source_uuid = models.UUIDField(unique=False, null=True)
Beispiel #22
0
class Image(OpenLedgerModel):
    identifier = models.UUIDField(
        unique=True,
        db_index=True,
        help_text="Our unique identifier for a CC work.")

    provider = models.CharField(
        max_length=80,
        blank=True,
        null=True,
        db_index=True,
        help_text="The content provider, e.g. Flickr, 500px...")

    source = models.CharField(
        max_length=80,
        blank=True,
        null=True,
        db_index=True,
        help_text="The source of the data, meaning a particular dataset. Source"
        " and provider can be different: the Google Open Images "
        "dataset is source=openimages., but provider=Flickr.")

    foreign_identifier = models.CharField(
        unique=True,
        max_length=1000,
        blank=True,
        null=True,
        db_index=True,
        help_text="The identifier provided by the upstream source.")

    foreign_landing_url = models.CharField(
        max_length=1000,
        blank=True,
        null=True,
        help_text="The landing page of the work.")

    url = models.URLField(unique=True,
                          max_length=1000,
                          help_text="The actual URL to the image.")

    thumbnail = models.URLField(
        max_length=1000,
        blank=True,
        null=True,
        help_text="The thumbnail for the image, if any.")

    width = models.IntegerField(blank=True, null=True)
    height = models.IntegerField(blank=True, null=True)

    filesize = models.IntegerField(blank=True, null=True)

    license = models.CharField(max_length=50)

    license_version = models.CharField(max_length=25, blank=True, null=True)

    creator = models.CharField(max_length=2000, blank=True, null=True)

    creator_url = models.URLField(max_length=2000, blank=True, null=True)

    title = models.CharField(max_length=2000, blank=True, null=True)

    tags = JSONField(blank=True, null=True)

    tags_list = ArrayField(models.CharField(max_length=255),
                           blank=True,
                           null=True)

    last_synced_with_source = models.DateTimeField(blank=True,
                                                   null=True,
                                                   db_index=True)

    removed_from_source = models.BooleanField(default=False)

    meta_data = JSONField(blank=True, null=True)

    view_count = models.IntegerField(default=0)

    watermarked = models.NullBooleanField(blank=True, null=True)

    @property
    def license_url(self):
        _license = str(self.license)
        license_version = str(self.license_version)
        return get_license_url(_license, license_version)

    @property
    def attribution(self):
        _license = str(self.license)
        license_version = str(self.license_version)
        if self.title:
            title = '"' + str(self.title) + '"'
        else:
            title = 'This work'
        if self.creator:
            creator = 'by ' + str(self.creator) + ' '
        else:
            creator = ''
        attribution = ATTRIBUTION.format(title=title,
                                         creator=creator,
                                         _license=_license.upper(),
                                         version=license_version,
                                         license_url=str(self.license_url))
        return attribution

    def image_tag(self):
        return mark_safe('<img src="%s" width="150" />' % self.url)

    image_tag.short_description = 'Image'

    class Meta:
        db_table = 'image'
        ordering = ['-created_on']
Beispiel #23
0
 def test_model_field_formfield_size(self):
     model_field = ArrayField(models.CharField(max_length=27), size=4)
     form_field = model_field.formfield()
     self.assertIsInstance(form_field, SimpleArrayField)
     self.assertEqual(form_field.max_length, 4)
Beispiel #24
0
class Analysis(models.Model):
    stopword = models.BooleanField(default=False)
    words = ArrayField(models.TextField(null=False, default=''), size=25)
    timestamp = models.DateTimeField(auto_now_add=False, null=True, blank=True)
    text = models.TextField(null=False, default='')
Beispiel #25
0
class Router(models.Model):
    router_name = models.CharField(max_length=100)
    router_ip = models.CharField(max_length=100)
    router_apps = ArrayField(models.CharField(max_length=100))
Beispiel #26
0
class Company(ArchivableModel, BaseModel):
    """Representation of the company."""
    class TransferReason(models.TextChoices):
        DUPLICATE = ('duplicate', 'Duplicate record')

    class ExportPotentialScore(models.TextChoices):
        VERY_HIGH = ('very_high', 'Very High')
        HIGH = ('high', 'High')
        MEDIUM = ('medium', 'Medium')
        LOW = ('low', 'Low')
        VERY_LOW = ('very_low', 'Very Low')

    class GreatProfileStatus(models.TextChoices):
        PUBLISHED = ('published', 'Published')
        UNPUBLISHED = ('unpublished', 'Unpublished')

        __empty__ = 'No profile or not known'

    class ExportSegment(models.TextChoices):
        HEP = ('hep', ' High export potential')
        NON_HEP = ('non-hep', 'Not high export potential')

        __empty__ = 'No export segment or not known'

    class ExportSubSegment(models.TextChoices):
        SUSTAIN_NURTURE_AND_GROW = (
            'sustain_nurture_and_grow',
            'Sustain: nurture & grow',
        )
        SUSTAIN_DEVELOP_EXPORT_CAPABILITY = (
            'sustain_develop_export_capability',
            'Sustain: develop export capability',
        )
        SUSTAIN_COMMUNICATE_BENEFITS = (
            'sustain_communicate_benefits',
            'Sustain: communicate benefits',
        )
        SUSTAIN_INCREASE_COMPETITIVENESS = (
            'sustain_increase_competitiveness',
            'Sustain: increase competitiveness',
        )
        REASSURE_NURTURE_AND_GROW = (
            'reassure_nurture_and_grow',
            'Reassure: nurture & grow',
        )
        REASSURE_DEVELOP_EXPORT_CAPABILITY = (
            'reassure_develop_export_capability',
            'Reassure: develop export capability',
        )
        REASSURE_LEAVE_BE = (
            'reassure_leave_be',
            'Reassure: leave be',
        )
        REASSURE_CHANGE_THE_GAME = (
            'reassure_change_the_game',
            'Reassure: change the game',
        )
        PROMOTE_DEVELOP_EXPORT_CAPABILITY = (
            'promote_develop_export_capability',
            'Promote: develop export capability',
        )
        PROMOTE_COMMUNICATE_BENEFITS = (
            'promote_communicate_benefits',
            'Promote: communicate benefits',
        )
        PROMOTE_CHANGE_THE_GAME = (
            'promote_change_the_game',
            'Promote: change the game',
        )
        CHALLENGE = (
            'challenge',
            'Challenge',
        )

        __empty__ = 'No sub export segment or not known'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    name = models.CharField(max_length=MAX_LENGTH)
    reference_code = models.CharField(max_length=MAX_LENGTH, blank=True)
    company_number = models.CharField(max_length=MAX_LENGTH,
                                      blank=True,
                                      null=True)
    vat_number = models.CharField(max_length=MAX_LENGTH, blank=True)
    duns_number = models.CharField(
        blank=True,
        null=True,
        help_text=
        'Dun & Bradstreet unique identifier. Nine-digit number with leading zeros.',
        max_length=9,
        unique=True,
        validators=[
            MinLengthValidator(9),
            MaxLengthValidator(9),
            integer_validator,
        ],
    )
    trading_names = ArrayField(
        models.CharField(max_length=settings.CHAR_FIELD_MAX_LENGTH),
        blank=True,
        default=list,
    )
    business_type = models.ForeignKey(
        metadata_models.BusinessType,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )
    sector = TreeForeignKey(
        metadata_models.Sector,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )
    employee_range = models.ForeignKey(
        metadata_models.EmployeeRange,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text=
        ('Not used when duns_number is set. In that case, use number_of_employees instead.'
         ),
    )
    number_of_employees = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text='Only used when duns_number is set.',
    )
    is_number_of_employees_estimated = models.BooleanField(
        null=True,
        blank=True,
        help_text='Only used when duns_number is set.',
    )
    turnover_range = models.ForeignKey(
        metadata_models.TurnoverRange,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text=
        'Not used when duns_number is set. In that case, use turnover instead.',
    )
    turnover = models.BigIntegerField(
        null=True,
        blank=True,
        help_text='In USD. Only used when duns_number is set.',
        validators=[MinValueValidator(0)],
    )
    is_turnover_estimated = models.BooleanField(
        null=True,
        blank=True,
        help_text='Only used when duns_number is set.',
    )
    export_to_countries = models.ManyToManyField(
        metadata_models.Country,
        blank=True,
        related_name='companies_exporting_to',
    )
    future_interest_countries = models.ManyToManyField(
        metadata_models.Country,
        blank=True,
        related_name='companies_with_future_interest',
    )
    description = models.TextField(blank=True, null=True)
    website = models.URLField(max_length=MAX_LENGTH, blank=True, null=True)
    uk_region = models.ForeignKey(
        metadata_models.UKRegion,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )

    # address is the main location for the business, it could be the trading address
    # or the registered address or a completely different address
    address_1 = models.CharField(max_length=MAX_LENGTH, blank=True)
    address_2 = models.CharField(max_length=MAX_LENGTH, blank=True)
    address_town = models.CharField(max_length=MAX_LENGTH, blank=True)
    address_county = models.CharField(max_length=MAX_LENGTH, blank=True)
    address_area = models.ForeignKey(
        metadata_models.AdministrativeArea,
        related_name='companies_with_address_area',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )
    address_country = models.ForeignKey(
        metadata_models.Country,
        blank=True,
        null=True,
        on_delete=models.PROTECT,
        related_name='companies_with_country_address',
    )
    address_postcode = models.CharField(max_length=MAX_LENGTH, blank=True)

    registered_address_1 = models.CharField(max_length=MAX_LENGTH, blank=True)
    registered_address_2 = models.CharField(max_length=MAX_LENGTH, blank=True)
    registered_address_town = models.CharField(max_length=MAX_LENGTH,
                                               blank=True)
    registered_address_area = models.ForeignKey(
        metadata_models.AdministrativeArea,
        related_name='companies_with_registered_address_area',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )

    registered_address_county = models.CharField(max_length=MAX_LENGTH,
                                                 blank=True)
    registered_address_country = models.ForeignKey(
        metadata_models.Country,
        related_name='companies_with_country_registered_address',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )
    registered_address_postcode = models.CharField(max_length=MAX_LENGTH,
                                                   blank=True)

    headquarter_type = models.ForeignKey(
        metadata_models.HeadquarterType,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )
    one_list_tier = models.ForeignKey(
        OneListTier,
        blank=True,
        null=True,
        on_delete=models.PROTECT,
    )
    global_headquarters = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='subsidiaries',
    )
    one_list_account_owner = models.ForeignKey(
        'Advisor',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='one_list_owned_companies',
        help_text='Global account manager',
    )
    export_experience_category = models.ForeignKey(
        ExportExperienceCategory,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
    )
    archived_documents_url_path = models.CharField(
        max_length=MAX_LENGTH,
        blank=True,
        help_text=
        'Legacy field. File browser path to the archived documents for this company.',
    )
    transferred_to = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='transferred_from',
        help_text='Where data about this company was transferred to.',
    )
    transfer_reason = models.CharField(
        max_length=MAX_LENGTH,
        blank=True,
        choices=TransferReason.choices,
        help_text='The reason data for this company was transferred.',
    )
    transferred_on = models.DateTimeField(blank=True, null=True)
    transferred_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='+',
    )
    dnb_investigation_id = models.UUIDField(
        null=True,
        blank=True,
        unique=True,
        help_text=
        ('The ID for a new company investigation with D&B. This ID is provided by dnb-service.'
         ),
    )
    pending_dnb_investigation = models.BooleanField(
        default=False,
        help_text='Whether this company is to be investigated by DNB.',
    )
    export_potential = models.CharField(
        max_length=MAX_LENGTH,
        null=True,
        blank=True,
        choices=ExportPotentialScore.choices,
        help_text=
        'Score that signifies export potential, imported from Data Science',
    )
    great_profile_status = models.CharField(
        max_length=MAX_LENGTH,
        null=True,
        blank=True,
        choices=GreatProfileStatus.choices,
        help_text=
        'Whether this company has a profile and agreed to be published or not',
    )
    global_ultimate_duns_number = models.CharField(
        blank=True,
        help_text='Dun & Bradstreet unique identifier for global ultimate.',
        max_length=9,
        validators=[
            MinLengthValidator(9),
            MaxLengthValidator(9),
            integer_validator,
        ],
        db_index=True,
    )
    dnb_modified_on = models.DateTimeField(
        blank=True,
        null=True,
        help_text='Last updated from D&B',
        db_index=True,
    )
    export_segment = models.CharField(
        max_length=MAX_LENGTH,
        blank=True,
        default='',
        help_text='Segmentation of export',
        choices=ExportSegment.choices,
    )
    export_sub_segment = models.CharField(
        max_length=MAX_LENGTH,
        blank=True,
        default='',
        help_text='Sub-Segmentation of export',
        choices=ExportSubSegment.choices,
    )

    def __str__(self):
        """Admin displayed human readable name."""
        return self.name

    def get_absolute_url(self):
        """URL to the object in the Data Hub internal front end."""
        return get_front_end_url(self)

    class Meta:
        verbose_name_plural = 'companies'
        permissions = (
            (CompanyPermission.view_company_document.value,
             'Can view company document'),
            (CompanyPermission.view_company_timeline.value,
             'Can view company timeline'),
            (CompanyPermission.export_company.value, 'Can export company'),
            (
                CompanyPermission.change_regional_account_manager.value,
                'Can change regional account manager',
            ),
            (
                CompanyPermission.
                change_one_list_tier_and_global_account_manager.value,
                'Can change one list tier and global account manager',
            ),
            (
                CompanyPermission.change_one_list_core_team_member.value,
                'Can change one list core team member associated with company',
            ),
            (CompanyPermission.view_export_win.value,
             'Can view company export win'),
        )
        indexes = [
            # For datasets app which includes API endpoints to be consumed by data-flow
            models.Index(fields=('created_on', 'id')),
        ]

    @property
    def uk_based(self):
        """Whether a company is based in the UK or not."""
        if not self.address_country:
            return None

        united_kingdom_id = uuid.UUID(
            constants.Country.united_kingdom.value.id)
        return self.address_country.id == united_kingdom_id

    @property
    def is_global_ultimate(self):
        """
        Whether this company is the global ultimate or not.
        """
        if not self.duns_number:
            return False
        return self.duns_number == self.global_ultimate_duns_number

    def mark_as_transferred(self, to, reason, user):
        """
        Marks a company record as having been transferred to another company record.

        This is used, for example, for marking a company as a duplicate record.
        """
        self.modified_by = user
        self.transfer_reason = reason
        self.transferred_by = user
        self.transferred_on = now()
        self.transferred_to = to

        display_reason = self.get_transfer_reason_display()

        archived_reason = (
            f'This record is no longer in use and its data has been transferred to {to} for the '
            f'following reason: {display_reason}.')

        # Note: archive() saves the model instance
        self.archive(user, archived_reason)

    def get_group_global_headquarters(self):
        """
        :returns: the Global Headquarters for the group that this company is part of.
        """
        if self.global_headquarters:
            return self.global_headquarters
        return self

    def get_one_list_group_tier(self):
        """
        :returns: the One List Tier of the group this company is part of.
        """
        return self.get_group_global_headquarters().one_list_tier

    def get_one_list_group_core_team(self):
        """
        :returns: the One List Core Team for the group that this company is part of
            as a list of dicts with `adviser` and `is_global_account_manager`.
        """
        group_global_headquarters = self.get_group_global_headquarters()
        global_account_manager = group_global_headquarters.one_list_account_owner

        core_team = []
        # add global account manager first
        if global_account_manager:
            core_team.append(
                {
                    'adviser': global_account_manager,
                    'is_global_account_manager': True,
                }, )

        # add all other core members excluding the global account manager
        # who might have already been added
        team_members = group_global_headquarters.one_list_core_team_members.exclude(
            adviser=global_account_manager, ).select_related(
                'adviser',
                'adviser__dit_team',
                'adviser__dit_team__uk_region',
                'adviser__dit_team__country',
            ).order_by(
                'adviser__first_name',
                'adviser__last_name',
            )

        core_team.extend({
            'adviser': team_member.adviser,
            'is_global_account_manager': False,
        } for team_member in team_members)
        return core_team

    def get_one_list_group_global_account_manager(self):
        """
        :returns: the One List Global Account Manager for the group that this
            company is part of.
        """
        group_global_headquarters = self.get_group_global_headquarters()
        return group_global_headquarters.one_list_account_owner

    def assign_one_list_account_manager_and_tier(
        self,
        one_list_account_owner,
        one_list_tier_id,
        modified_by,
    ):
        """Update the company's One List account manager and tier."""
        self.modified_by = modified_by
        self.one_list_account_owner = one_list_account_owner
        self.one_list_tier_id = one_list_tier_id
        self.save()

    def remove_from_one_list(self, modified_by):
        """
        Remove the company from the One List.

        This is done by unsetting the company's One List account manager and tier.
        """
        self.modified_by = modified_by
        self.one_list_account_owner = None
        self.one_list_tier = None
        self.save()

    def add_one_list_core_team_member(self, adviser):
        """Add Core team member to the company."""
        OneListCoreTeamMember.objects.get_or_create(adviser=adviser,
                                                    company=self)

    def delete_one_list_core_team_member(self, adviser):
        """Remove Core Team member from the company."""
        OneListCoreTeamMember.objects.filter(adviser=adviser,
                                             company=self).delete()

    def add_export_country(self,
                           country,
                           status,
                           record_date,
                           adviser,
                           track_history=False):
        """
        Add a company export_country, if it doesn't exist.
        If the company already exists and incoming status is different
        check if incoming record is newer and update.
        And send signal to track history.
        """
        export_country, created = CompanyExportCountry.objects.get_or_create(
            country=country,
            company=self,
            defaults={
                'status': status,
                'created_by': adviser,
                'modified_by': adviser,
            },
        )

        updated = False

        if not created:
            if export_country.status != status and export_country.modified_on < record_date:
                export_country.status = status
                export_country.modified_by = adviser
                export_country.save()
                updated = True

        if track_history and (created or updated):
            export_country_update_signal.send(
                sender=CompanyExportCountry,
                instance=export_country,
                created=created,
                by=adviser,
            )

    @transaction.atomic
    def delete_export_country(self, country_id, adviser):
        """Delete export country and send signal for tracking history"""
        export_country = self.export_countries.filter(
            country_id=country_id).first()
        if export_country:
            export_country_delete_signal.send(
                sender=CompanyExportCountry,
                instance=export_country,
                by=adviser,
            )
            export_country.delete()
Beispiel #27
0
class EventReceiveGroup(BaseModel):
    group_id = ArrayField(models.IntegerField())

    class Meta:
        db_table = 'event_receive_groups'
Beispiel #28
0
        if self.require_upper and value.upper is None:
            raise ValidationError("Upper datetime bound must be set")
        
    def formfield(self, **kwargs):
        defaults = {'form_class': DateTimeRangeFormField}
        defaults.update(kwargs)
        return super(DateTimeRange, self).formfield(**defaults)


class LowercaseTransform(Transform):
    lookup_name = 'array_lowercase'
    def as_sql(self, qn, connection):
        lhs, params = qn.compile(self.lhs)
        return "array_lowercase(%s)" % (lhs,), params


class SingleContainedByLookup(ContainedByLookup):
    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return "ARRAY[%s] <@ %s::%s[]" % (lhs, rhs, self.lhs.output_field.db_type(connection)), params


UUIDField.register_lookup(SingleContainedByLookup)
DateTimeRange.register_lookup(ContainedByLookup)
DateTimeRange.register_lookup(ContainsLookup)
DateTimeRange.register_lookup(OverlapLookup)
ArrayField.register_lookup(LowercaseTransform)
NativeArrayField.register_lookup(LowercaseTransform)
Beispiel #29
0
class EmailSubscriber(SuperModel):

    email = models.EmailField(max_length=255, unique=True)
    source = models.CharField(max_length=50)
    active = models.BooleanField(default=True)
    newsletter = models.BooleanField(default=True)
    preferences = JSONField(default=dict)
    metadata = JSONField(default=dict, blank=True)
    priv = models.CharField(max_length=30, default='')
    github = models.CharField(max_length=255, default='', blank=True)
    keywords = ArrayField(models.CharField(max_length=200),
                          blank=True,
                          default=list)
    profile = models.ForeignKey('dashboard.Profile',
                                on_delete=models.CASCADE,
                                related_name='email_subscriptions',
                                null=True,
                                blank=True)
    form_submission_records = JSONField(default=list, blank=True)

    def __str__(self):
        return self.email

    def set_priv(self):
        self.priv = token_hex(16)[:29]

    def should_send_email_type_to(self, email_type):
        is_on_global_suppression_list = EmailSupressionList.objects.filter(
            email__iexact=self.email).exists()
        if is_on_global_suppression_list:
            return False

        should_suppress = self.preferences.get('suppression_preferences',
                                               {}).get(email_type, False)
        return not should_suppress

    def set_should_send_email_type_to(self, key, should_send):
        suppression_preferences = self.preferences.get(
            'suppression_preferences', {})
        suppression_preferences[
            key] = not should_send  #db = suppressed? request format = send?
        self.preferences['suppression_preferences'] = suppression_preferences

    def build_email_preferences(self, form=None):
        from retail.emails import ALL_EMAILS, TRANSACTIONAL_EMAILS, MARKETING_EMAILS
        if form is None:
            form = {}

        suppression_preferences = self.preferences.get(
            'suppression_preferences', {})

        # update from legacy email preferences
        level = self.preferences.pop('level', None)
        if level:
            if level == 'lite1':
                for email_tuple in MARKETING_EMAILS:
                    key, __, __ = email_tuple
                    suppression_preferences[key] = True
                for email_tuple in TRANSACTIONAL_EMAILS:
                    key, __, __ = email_tuple
                    suppression_preferences[key] = False
            elif level == 'lite':
                for email_tuple in MARKETING_EMAILS:
                    key, __, __ = email_tuple
                    suppression_preferences[key] = False
                for email_tuple in TRANSACTIONAL_EMAILS:
                    key, __, __ = email_tuple
                    suppression_preferences[key] = True
            else:
                for email_tuple in ALL_EMAILS:
                    key, __, __ = email_tuple
                    suppression_preferences[key] = False

        # update from form
        for email_tuple in ALL_EMAILS:
            key, __, __ = email_tuple
            if key in form.keys():
                suppression_preferences[key] = bool(form[key])

        # save and return
        self.preferences['suppression_preferences'] = suppression_preferences
        return suppression_preferences

    @property
    def is_eu(self):
        from app.utils import get_country_from_ip
        try:
            ip_addresses = self.metadata.get('ip')
            if ip_addresses:
                for ip_address in ip_addresses:
                    country = get_country_from_ip(ip_address)
                    if country.continent.code == 'EU':
                        return True
        except Exception:
            # Cowardly pass on everything for the moment.
            pass
        return False
Beispiel #30
0
 def test_field_checks(self):
     field = ArrayField(models.CharField())
     field.set_attributes_from_name('field')
     errors = field.check()
     self.assertEqual(len(errors), 1)
     self.assertEqual(errors[0].id, 'postgres.E001')
Beispiel #31
0
class User(AbstractBaseUser, PermissionsMixin):
    ACTIVATION_NONE = 0
    ACTIVATION_USER = 1
    ACTIVATION_ADMIN = 2

    SUBSCRIPTION_NONE = 0
    SUBSCRIPTION_NOTIFY = 1
    SUBSCRIPTION_ALL = 2

    SUBSCRIPTION_CHOICES = [
        (SUBSCRIPTION_NONE, _("No")),
        (SUBSCRIPTION_NOTIFY, _("Notify")),
        (SUBSCRIPTION_ALL, _("Notify with e-mail")),
    ]

    LIMIT_INVITES_TO_NONE = 0
    LIMIT_INVITES_TO_FOLLOWED = 1
    LIMIT_INVITES_TO_NOBODY = 2

    LIMIT_INVITES_TO_CHOICES = [
        (LIMIT_INVITES_TO_NONE, _("Everybody")),
        (LIMIT_INVITES_TO_FOLLOWED, _("Users I follow")),
        (LIMIT_INVITES_TO_NOBODY, _("Nobody")),
    ]

    # Note that "username" field is purely for shows.
    # When searching users by their names, always use lowercased string
    # and slug field instead that is normalized around DB engines
    # differences in case handling.
    username = models.CharField(max_length=30)
    slug = models.CharField(max_length=30, unique=True)

    # Misago stores user email in two fields:
    # "email" holds normalized email address
    # "email_hash" is lowercase hash of email address used to identify account
    # as well as enforcing on database level that no more than one user can be
    # using one email address
    email = models.EmailField(max_length=255, db_index=True)
    email_hash = models.CharField(max_length=32, unique=True)

    joined_on = models.DateTimeField(_("joined on"), default=timezone.now)
    joined_from_ip = models.GenericIPAddressField(null=True, blank=True)
    is_hiding_presence = models.BooleanField(default=False)

    rank = models.ForeignKey("Rank",
                             null=True,
                             blank=True,
                             on_delete=models.deletion.PROTECT)
    title = models.CharField(max_length=255, null=True, blank=True)
    requires_activation = models.PositiveIntegerField(default=ACTIVATION_NONE)

    is_staff = models.BooleanField(
        _("staff status"),
        default=False,
        help_text=_("Designates whether the user can log into admin sites."),
    )

    roles = models.ManyToManyField("misago_acl.Role")
    acl_key = models.CharField(max_length=12, null=True, blank=True)

    is_active = models.BooleanField(
        _("active"),
        db_index=True,
        default=True,
        help_text=_(
            "Designates whether this user should be treated as active. "
            "Unselect this instead of deleting accounts."),
    )
    is_active_staff_message = models.TextField(null=True, blank=True)

    is_deleting_account = models.BooleanField(default=False)

    avatar_tmp = models.ImageField(max_length=255,
                                   upload_to=avatars.store.upload_to,
                                   null=True,
                                   blank=True)
    avatar_src = models.ImageField(max_length=255,
                                   upload_to=avatars.store.upload_to,
                                   null=True,
                                   blank=True)
    avatar_crop = models.CharField(max_length=255, null=True, blank=True)
    avatars = JSONField(null=True, blank=True)
    is_avatar_locked = models.BooleanField(default=False)
    avatar_lock_user_message = models.TextField(null=True, blank=True)
    avatar_lock_staff_message = models.TextField(null=True, blank=True)

    signature = models.TextField(null=True, blank=True)
    signature_parsed = models.TextField(null=True, blank=True)
    signature_checksum = models.CharField(max_length=64, null=True, blank=True)
    is_signature_locked = models.BooleanField(default=False)
    signature_lock_user_message = models.TextField(null=True, blank=True)
    signature_lock_staff_message = models.TextField(null=True, blank=True)

    followers = models.PositiveIntegerField(default=0)
    following = models.PositiveIntegerField(default=0)

    follows = models.ManyToManyField("self",
                                     related_name="followed_by",
                                     symmetrical=False)
    blocks = models.ManyToManyField("self",
                                    related_name="blocked_by",
                                    symmetrical=False)

    limits_private_thread_invites_to = models.PositiveIntegerField(
        default=LIMIT_INVITES_TO_NONE, choices=LIMIT_INVITES_TO_CHOICES)
    unread_private_threads = models.PositiveIntegerField(default=0)
    sync_unread_private_threads = models.BooleanField(default=False)

    subscribe_to_started_threads = models.PositiveIntegerField(
        default=SUBSCRIPTION_NONE, choices=SUBSCRIPTION_CHOICES)
    subscribe_to_replied_threads = models.PositiveIntegerField(
        default=SUBSCRIPTION_NONE, choices=SUBSCRIPTION_CHOICES)

    threads = models.PositiveIntegerField(default=0)
    posts = models.PositiveIntegerField(default=0, db_index=True)

    last_posted_on = models.DateTimeField(null=True, blank=True)

    profile_fields = HStoreField(default=dict)
    agreements = ArrayField(models.PositiveIntegerField(), default=list)

    USERNAME_FIELD = "slug"
    REQUIRED_FIELDS = ["email"]

    objects = UserManager()

    class Meta:
        indexes = [
            PgPartialIndex(fields=["is_staff"], where={"is_staff": True}),
            PgPartialIndex(fields=["requires_activation"],
                           where={"requires_activation__gt": 0}),
            PgPartialIndex(fields=["is_deleting_account"],
                           where={"is_deleting_account": True}),
        ]

    def clean(self):
        self.username = self.normalize_username(self.username)
        self.email = UserManager.normalize_email(self.email)

    def lock(self):
        """locks user in DB, shortcut for locking user model in views"""
        return User.objects.select_for_update().get(pk=self.pk)

    def delete(self, *args, **kwargs):
        if kwargs.pop("delete_content", False):
            self.delete_content()

        self.anonymize_data()

        avatars.delete_avatar(self)

        return super().delete(*args, **kwargs)

    def delete_content(self):
        from ..signals import delete_user_content

        delete_user_content.send(sender=self)

    def mark_for_delete(self):
        self.is_active = False
        self.is_deleting_account = True
        self.save(update_fields=["is_active", "is_deleting_account"])

    def anonymize_data(self):
        """Replaces username with anonymized one, then send anonymization signal.

        Items associated with this user then anonymize their user-specific data
        like username or IP addresses.
        """
        self.username = settings.MISAGO_ANONYMOUS_USERNAME
        self.slug = slugify(self.username)

        from ..signals import anonymize_user_data

        anonymize_user_data.send(sender=self)

    @property
    def requires_activation_by_admin(self):
        return self.requires_activation == self.ACTIVATION_ADMIN

    @property
    def requires_activation_by_user(self):
        return self.requires_activation == self.ACTIVATION_USER

    @property
    def can_be_messaged_by_everyone(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_NONE

    @property
    def can_be_messaged_by_followed(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_FOLLOWED

    @property
    def can_be_messaged_by_nobody(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_NOBODY

    @property
    def has_valid_signature(self):
        return is_user_signature_valid(self)

    def get_absolute_url(self):
        return reverse("misago:user",
                       kwargs={
                           "slug": self.slug,
                           "pk": self.pk
                       })

    def get_username(self):
        """dirty hack: return real username instead of normalized slug"""
        return self.username

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

    def get_real_name(self):
        return self.profile_fields.get("real_name")

    def set_username(self, new_username, changed_by=None):
        new_username = self.normalize_username(new_username)
        if new_username != self.username:
            old_username = self.username
            self.username = new_username
            self.slug = slugify(new_username)

            if self.pk:
                changed_by = changed_by or self
                namechange = self.record_name_change(changed_by, new_username,
                                                     old_username)

                from ..signals import username_changed

                username_changed.send(sender=self)

                return namechange

    def record_name_change(self, changed_by, new_username, old_username):
        return self.namechanges.create(
            new_username=new_username,
            old_username=old_username,
            changed_by=changed_by,
            changed_by_username=changed_by.username,
        )

    def set_email(self, new_email):
        self.email = UserManager.normalize_email(new_email)
        self.email_hash = hash_email(new_email)

    def get_any_title(self):
        return self.title or self.rank.title or self.rank.name

    def get_roles(self):
        roles_pks = []
        roles_dict = {}

        for role in self.roles.all():
            roles_pks.append(role.pk)
            role.origin = self
            roles_dict[role.pk] = role

        if self.rank:
            for role in self.rank.roles.all():
                if role.pk not in roles_pks:
                    role.origin = self.rank
                    roles_pks.append(role.pk)
                    roles_dict[role.pk] = role

        return [roles_dict[r] for r in sorted(roles_pks)]

    def update_acl_key(self):
        roles_pks = []
        for role in self.get_roles():
            if role.origin == "self":
                roles_pks.append("u%s" % role.pk)
            else:
                roles_pks.append("%s:%s" % (self.rank.pk, role.pk))

        self.acl_key = md5(",".join(roles_pks).encode()).hexdigest()[:12]

    def email_user(self, subject, message, from_email=None, **kwargs):
        """sends an email to this user (for compat with Django)"""
        send_mail(subject, message, from_email, [self.email], **kwargs)

    def is_following(self, user_or_id):
        try:
            user_id = user_or_id.id
        except AttributeError:
            user_id = user_or_id

        try:
            self.follows.get(id=user_id)
            return True
        except User.DoesNotExist:
            return False

    def is_blocking(self, user_or_id):
        try:
            user_id = user_or_id.id
        except AttributeError:
            user_id = user_or_id

        try:
            self.blocks.get(id=user_id)
            return True
        except User.DoesNotExist:
            return False
Beispiel #32
0
class KBEntry(NOCModel):
    """
    KB Entry
    """
    class Meta(object):
        verbose_name = "KB Entry"
        verbose_name_plural = "KB Entries"
        app_label = "kb"
        db_table = "kb_kbentry"
        ordering = ("id", )

    subject = models.CharField("Subject", max_length=256)
    body = models.TextField("Body")
    language = models.ForeignKey(
        Language,
        verbose_name="Language",
        limit_choices_to={"is_active": True},
        on_delete=models.CASCADE,
    )
    markup_language = models.CharField("Markup Language",
                                       max_length=16,
                                       choices=[(x, x) for x in loader])
    #
    labels = ArrayField(models.CharField(max_length=250),
                        blank=True,
                        null=True,
                        default=list)
    effective_labels = ArrayField(models.CharField(max_length=250),
                                  blank=True,
                                  null=True,
                                  default=list)

    def __str__(self):
        if self.id:
            return "KB%d: %s" % (self.id, self.subject)
        else:
            return "New: %s" % self.subject

    def save(self, *args, **kwargs):
        """
        save model, compute body's diff and save event history
        """
        from noc.core.middleware.tls import get_user
        from noc.kb.models.kbentryhistory import KBEntryHistory

        user = get_user()
        if self.id:
            old_body = KBEntry.objects.get(id=self.id).body
        else:
            old_body = ""
        super().save(*args, **kwargs)
        if old_body != self.body:
            diff = "\n".join(
                difflib.unified_diff(self.body.splitlines(),
                                     old_body.splitlines()))
            KBEntryHistory(
                kb_entry=self,
                user=user,
                diff=diff,
                timestamp=datetime.datetime.now().replace(microsecond=0),
            ).save()

    @property
    def parser(self):
        """
        Wiki parser class
        """
        return loader[self.markup_language]

    @property
    def html(self):
        """
        Returns parsed HTML
        """
        return self.parser.to_html(self)

    @property
    def last_history(self):
        """
        Returns latest KBEntryHistory record
        """
        from .kbentryhistory import KBEntryHistory

        d = KBEntryHistory.objects.filter(
            kb_entry=self).order_by("-timestamp")[:1]
        if d:
            return d[0]
        return None

    @classmethod
    def last_modified(cls, num=20):
        """
        Returns a list of last modified KB Entries
        """
        from django.db import connection

        c = connection.cursor()
        c.execute("""
            SELECT kb_entry_id,MAX(timestamp)
            FROM kb_kbentryhistory
            GROUP BY 1
            ORDER BY 2 DESC
            LIMIT %d""" % num)
        return [KBEntry.objects.get(id=r[0]) for r in c.fetchall()]

    def log_preview(self, user):
        """
        Write article preview log
        """
        from .kbentrypreviewlog import KBEntryPreviewLog

        KBEntryPreviewLog(kb_entry=self, user=user).save()

    @property
    def preview_count(self):
        """
        Returns preview count
        """
        return self.kbentrypreviewlog_set.count()

    @classmethod
    def most_popular(cls, num=20):
        """
        Returns most popular articles
        """
        from django.db import connection

        c = connection.cursor()
        c.execute("""
            SELECT kb_entry_id,COUNT(*)
            FROM kb_kbentrypreviewlog
            GROUP BY 1
            ORDER BY 2 DESC
            LIMIT %d""" % num)
        return [KBEntry.objects.get(id=r[0]) for r in c.fetchall()]

    @classmethod
    def upload_to(cls, instance, filename):
        """
        Callable for KBEntryAttachment.file.upload_to
        """
        return "/kb/%d/%s" % (instance.kb_entry.id, filename)

    @property
    def visible_attachments(self):
        """
        Returns a list of visible attachments
        """
        return [{
            "name": x.name,
            "size": x.size,
            "mtime": x.mtime,
            "description": x.description
        } for x in self.kbentryattachment_set.filter(
            is_hidden=False).order_by("name")]

    @property
    def has_visible_attachments(self):
        return self.kbentryattachment_set.filter(is_hidden=False).exists()

    @classmethod
    def can_set_label(cls, label):
        if label.enable_kbentry:
            return True
        return False
Beispiel #33
0
class EigenschapSpecificatie(models.Model):
    """
    Met de ‘subattributen’ (van deze groepattribuutsoort) Groep, Formaat, Lengte, Kardinaliteit en Waardenverzameling
    wordt een eigenschap gedetailleerd gespecificeerd. Dit vindt alleen plaats als de eigenschap niet gespecificeerd is
    door middel van het groepattribuutsoort ‘Referentie naar eigenschap’.
    """

    groep = models.CharField(  # waardenverzameling Letters, cijfers en liggende streepjes
        _("groep"),
        max_length=32,
        blank=True,
        validators=[validate_letters_numbers_underscores],
        help_text=_(
            "Benaming van het object of groepattribuut waarvan de EIGENSCHAP een "
            "inhoudelijk gegeven specificeert."),
    )
    # waardenverzameling gedefinieerd als tekst, getal, datum (jjjjmmdd), datum/tijd (jjjjmmdduummss), met AN20
    formaat = models.CharField(
        _("formaat"),
        max_length=20,
        choices=FormaatChoices.choices,
        help_text=
        _("Het soort tekens waarmee waarden van de EIGENSCHAP kunnen worden vastgelegd."
          ),
    )
    lengte = models.CharField(
        _("lengte"),
        max_length=14,
        help_text=
        _("Het aantal karakters (lengte) waarmee waarden van de EIGENSCHAP worden vastgelegd."
          ),
    )
    kardinaliteit = models.CharField(
        _("kardinaliteit"),
        max_length=3,
        validators=[validate_kardinaliteit],
        help_text=
        _("Het aantal mogelijke voorkomens van waarden van deze EIGENSCHAP bij een zaak van het ZAAKTYPE."
          ),
    )

    waardenverzameling = ArrayField(
        models.CharField(_("waardenverzameling"), max_length=100),
        blank=True,
        help_text=_("Waarden die deze EIGENSCHAP kan hebben."),
    )

    class Meta:
        verbose_name = _("Eigenschap specificatie")
        verbose_name_plural = _("Eigenschap specificaties")

    def clean(self):
        """
        waardenverzameling voor veld lengte hangt af van formaat

        Als Formaat = tekst: 0-255
        Als Formaat = getal: n,m (n: aantal cijfers geheel getal, m:
        aantal decimalen)
        Als Formaat = datum: 8
        Als Formaat = datum/tijd: 14
        """
        if self.formaat == FormaatChoices.tekst:
            try:
                error = not (0 <= int(self.lengte) <= 255)
            except Exception:  # (ValueError, TypeError) ?
                error = True
            if error:
                raise ValidationError(
                    _("Als formaat tekst is, moet de lengte een getal tussen de 0 en 255 zijn."
                      ))

        elif self.formaat == FormaatChoices.getal:
            try:  # specificatie spreekt over kommagescheiden decimaal, wij nemen echter aan dat het punt gescheiden is
                Decimal(self.lengte)
            except (InvalidOperation, TypeError):
                raise ValidationError(
                    _("Als formaat getal is, moet de lengte een (kommagescheiden) getal zijn."
                      ))

        elif self.formaat == FormaatChoices.datum:
            if self.lengte != 8:
                raise ValidationError(
                    _("Als formaat datum is, moet de lengte 8 zijn."))

        elif self.formaat == FormaatChoices.datum_tijd:
            if self.lengte != 14:
                raise ValidationError(
                    _("Als formaat datum/tijd is, moet de lengte 14 zijn."))
Beispiel #34
0
class IntegerRangeArrayModel(PostgreSQLModel):
    field = ArrayField(IntegerRangeField())
Beispiel #35
0
 def test_invalid_base_fields(self):
     field = ArrayField(models.ManyToManyField('postgres_tests.IntegerArrayModel'))
     field.set_attributes_from_name('field')
     errors = field.check()
     self.assertEqual(len(errors), 1)
     self.assertEqual(errors[0].id, 'postgres.E002')
Beispiel #36
0
class LegalEntity(DataSourceTrackedModel):
    legal_entity_id = models.BigAutoField(primary_key=True, db_index=True)
    recipient_name = models.TextField(blank=True,
                                      verbose_name="Recipient Name",
                                      null=True)
    location = models.ForeignKey("references.Location",
                                 models.DO_NOTHING,
                                 null=True)
    parent_recipient_unique_id = models.TextField(
        blank=True,
        null=True,
        verbose_name="Parent DUNS Number",
        db_index=True)
    parent_recipient_name = models.TextField(
        blank=True, verbose_name="Parent Recipient Name", null=True)
    vendor_doing_as_business_name = models.TextField(blank=True, null=True)
    vendor_phone_number = models.TextField(blank=True, null=True)
    vendor_fax_number = models.TextField(blank=True, null=True)
    business_types = models.TextField(blank=True, null=True, db_index=True)
    business_types_description = models.TextField(blank=True, null=True)
    """
    Business Type Categories
    Make sure to leave default as 'list', as [] would share across instances

    Possible entries:

    category_business
    - small_business
    - other_than_small_business
    - corporate_entity_tax_exempt
    - corporate_entity_not_tax_exempt
    - partnership_or_limited_liability_partnership
    - sole_proprietorship
    - manufacturer_of_goods
    - subchapter_s_corporation
    - limited_liability_corporation

    minority_owned_business
    - alaskan_native_owned_business
    - american_indian_owned_business
    - asian_pacific_american_owned_business
    - black_american_owned_business
    - hispanic_american_owned_business
    - native_american_owned_business
    - native_hawaiian_owned_business
    - subcontinent_asian_indian_american_owned_business
    - tribally_owned_business
    - other_minority_owned_business

    women_owned_business
    - women_owned_small_business
    - economically_disadvantaged_women_owned_small_business
    - joint_venture_women_owned_small_business
    - joint_venture_economically_disadvantaged_women_owned_small_business

    veteran_owned_business
    - service_disabled_veteran_owned_business

    special_designations
    - 8a_program_participant
    - ability_one_program
    - dot_certified_disadvantaged_business_enterprise
    - emerging_small_business
    - federally_funded_research_and_development_corp
    - historically_underutilized_business_firm
    - labor_surplus_area_firm
    - sba_certified_8a_joint_venture
    - self_certified_small_disadvanted_business
    - small_agricultural_cooperative
    - small_disadvantaged_business
    - community_developed_corporation_owned_firm
    - us_owned_business
    - foreign_owned_and_us_located_business
    - foreign_owned_and_located_business
    - foreign_government
    - international_organization
    - domestic_shelter
    - hospital
    - veterinary_hospital

    nonprofit
    - foundation
    - community_development_corporations

    higher_education
    - educational_institution
    - public_institution_of_higher_education
    - private_institution_of_higher_education
    - minority_serving_institution_of_higher_education
    - school_of_forestry
    - veterinary_college

    government
    - national_government
    - interstate_entity
    - regional_and_state_government
    - regional_organization
    - us_territory_or_possession
    - council_of_governments
    - local_government
    - indian_native_american_tribal_government
    - authorities_and_commissions

    individuals
    """
    business_categories = ArrayField(models.TextField(), default=list)

    recipient_unique_id = models.TextField(blank=True,
                                           default="",
                                           null=True,
                                           verbose_name="DUNS Number",
                                           db_index=True)
    limited_liability_corporation = models.NullBooleanField(blank=False,
                                                            default=False)
    sole_proprietorship = models.NullBooleanField(blank=False, default=False)
    partnership_or_limited_liability_partnership = models.NullBooleanField(
        blank=False, default=False)
    subchapter_scorporation = models.NullBooleanField(blank=False,
                                                      default=False)
    foundation = models.NullBooleanField(blank=False, default=False)
    for_profit_organization = models.NullBooleanField(blank=False,
                                                      default=False)
    nonprofit_organization = models.NullBooleanField(blank=False,
                                                     default=False)
    corporate_entity_tax_exempt = models.NullBooleanField(blank=False,
                                                          default=False)
    corporate_entity_not_tax_exempt = models.NullBooleanField(blank=False,
                                                              default=False)
    other_not_for_profit_organization = models.NullBooleanField(blank=False,
                                                                default=False)
    sam_exception = models.TextField(blank=True, null=True)
    city_local_government = models.NullBooleanField(blank=False, default=False)
    county_local_government = models.NullBooleanField(blank=False,
                                                      default=False)
    inter_municipal_local_government = models.NullBooleanField(blank=False,
                                                               default=False)
    local_government_owned = models.NullBooleanField(blank=False,
                                                     default=False)
    municipality_local_government = models.NullBooleanField(blank=False,
                                                            default=False)
    school_district_local_government = models.NullBooleanField(blank=False,
                                                               default=False)
    township_local_government = models.NullBooleanField(blank=False,
                                                        default=False)
    us_state_government = models.NullBooleanField(blank=False, default=False)
    us_federal_government = models.NullBooleanField(blank=False, default=False)
    federal_agency = models.NullBooleanField(blank=False, default=False)
    federally_funded_research_and_development_corp = models.NullBooleanField(
        blank=False, default=False)
    us_tribal_government = models.NullBooleanField(blank=False, default=False)
    foreign_government = models.NullBooleanField(blank=False, default=False)
    community_developed_corporation_owned_firm = models.NullBooleanField(
        blank=False, default=False)
    labor_surplus_area_firm = models.NullBooleanField(blank=False,
                                                      default=False)
    small_agricultural_cooperative = models.NullBooleanField(blank=False,
                                                             default=False)
    international_organization = models.NullBooleanField(blank=False,
                                                         default=False)
    us_government_entity = models.NullBooleanField(blank=False, default=False)
    emerging_small_business = models.NullBooleanField(blank=False,
                                                      default=False)
    c8a_program_participant = models.NullBooleanField(
        db_column="8a_program_participant",
        max_length=1,
        blank=False,
        default=False,
        verbose_name="8a Program Participant",
    )  # Field renamed because it wasn't a valid Python identifier.
    sba_certified_8a_joint_venture = models.NullBooleanField(blank=False,
                                                             default=False)
    dot_certified_disadvantage = models.NullBooleanField(blank=False,
                                                         default=False)
    self_certified_small_disadvantaged_business = models.NullBooleanField(
        blank=False, default=False)
    historically_underutilized_business_zone = models.NullBooleanField(
        blank=False, default=False)
    small_disadvantaged_business = models.NullBooleanField(blank=False,
                                                           default=False)
    the_ability_one_program = models.NullBooleanField(blank=False,
                                                      default=False)
    historically_black_college = models.NullBooleanField(blank=False,
                                                         default=False)
    c1862_land_grant_college = models.NullBooleanField(
        db_column="1862_land_grant_college",
        max_length=1,
        blank=False,
        default=False,
        verbose_name="1862 Land Grant College",
    )  # Field renamed because it wasn't a valid Python identifier.
    c1890_land_grant_college = models.NullBooleanField(
        db_column="1890_land_grant_college",
        max_length=1,
        blank=False,
        default=False,
        verbose_name="1890 Land Grant College",
    )  # Field renamed because it wasn't a valid Python identifier.
    c1994_land_grant_college = models.NullBooleanField(
        db_column="1994_land_grant_college",
        max_length=1,
        blank=False,
        default=False,
        verbose_name="1894 Land Grant College",
    )  # Field renamed because it wasn't a valid Python identifier.
    minority_institution = models.NullBooleanField(blank=False, default=False)
    private_university_or_college = models.NullBooleanField(blank=False,
                                                            default=False)
    school_of_forestry = models.NullBooleanField(blank=False, default=False)
    state_controlled_institution_of_higher_learning = models.NullBooleanField(
        blank=False, default=False)
    tribal_college = models.NullBooleanField(blank=False, default=False)
    veterinary_college = models.NullBooleanField(blank=False, default=False)
    educational_institution = models.NullBooleanField(blank=False,
                                                      default=False)
    alaskan_native_servicing_institution = models.NullBooleanField(
        blank=False,
        default=False,
        verbose_name="Alaskan Native Owned Servicing Institution")
    community_development_corporation = models.NullBooleanField(blank=False,
                                                                default=False)
    native_hawaiian_servicing_institution = models.NullBooleanField(
        blank=False, default=False)
    domestic_shelter = models.NullBooleanField(blank=False, default=False)
    manufacturer_of_goods = models.NullBooleanField(blank=False, default=False)
    hospital_flag = models.NullBooleanField(blank=False, default=False)
    veterinary_hospital = models.NullBooleanField(blank=False, default=False)
    hispanic_servicing_institution = models.NullBooleanField(blank=False,
                                                             default=False)
    woman_owned_business = models.NullBooleanField(blank=False, default=False)
    minority_owned_business = models.NullBooleanField(blank=False,
                                                      default=False)
    women_owned_small_business = models.NullBooleanField(blank=False,
                                                         default=False)
    economically_disadvantaged_women_owned_small_business = models.NullBooleanField(
        blank=False, default=False)
    joint_venture_women_owned_small_business = models.NullBooleanField(
        blank=False, default=False)
    joint_venture_economic_disadvantaged_women_owned_small_bus = models.NullBooleanField(
        blank=False, default=False)
    veteran_owned_business = models.NullBooleanField(blank=False,
                                                     default=False)
    service_disabled_veteran_owned_business = models.NullBooleanField(
        blank=False, default=False)
    contracts = models.NullBooleanField(blank=False, default=False)
    grants = models.NullBooleanField(blank=False, default=False)
    receives_contracts_and_grants = models.NullBooleanField(blank=False,
                                                            default=False)
    airport_authority = models.NullBooleanField(
        blank=False, default=False, verbose_name="Airport Authority")
    council_of_governments = models.NullBooleanField(blank=False,
                                                     default=False)
    housing_authorities_public_tribal = models.NullBooleanField(blank=False,
                                                                default=False)
    interstate_entity = models.NullBooleanField(blank=False, default=False)
    planning_commission = models.NullBooleanField(blank=False, default=False)
    port_authority = models.NullBooleanField(blank=False, default=False)
    transit_authority = models.NullBooleanField(blank=False, default=False)
    foreign_owned_and_located = models.NullBooleanField(blank=False,
                                                        default=False)
    american_indian_owned_business = models.NullBooleanField(
        blank=False,
        default=False,
        verbose_name="American Indian Owned Business")
    alaskan_native_owned_corporation_or_firm = models.NullBooleanField(
        blank=False,
        default=False,
        verbose_name="Alaskan Native Owned Corporation or Firm")
    indian_tribe_federally_recognized = models.NullBooleanField(blank=False,
                                                                default=False)
    native_hawaiian_owned_business = models.NullBooleanField(blank=False,
                                                             default=False)
    tribally_owned_business = models.NullBooleanField(blank=False,
                                                      default=False)
    asian_pacific_american_owned_business = models.NullBooleanField(
        blank=False,
        default=False,
        verbose_name="Asian Pacific American Owned business")
    black_american_owned_business = models.NullBooleanField(blank=False,
                                                            default=False)
    hispanic_american_owned_business = models.NullBooleanField(blank=False,
                                                               default=False)
    native_american_owned_business = models.NullBooleanField(blank=False,
                                                             default=False)
    subcontinent_asian_asian_indian_american_owned_business = models.NullBooleanField(
        blank=False, default=False)
    other_minority_owned_business = models.NullBooleanField(blank=False,
                                                            default=False)
    us_local_government = models.NullBooleanField(blank=False, default=False)
    undefinitized_action = models.TextField(blank=True, null=True)
    domestic_or_foreign_entity = models.TextField(blank=True,
                                                  null=True,
                                                  db_index=False)
    domestic_or_foreign_entity_description = models.TextField(null=True,
                                                              blank=True)
    division_name = models.TextField(blank=True, null=True)
    division_number = models.TextField(blank=True, null=True)
    last_modified_date = models.DateField(blank=True, null=True)
    certified_date = models.DateField(blank=True, null=True)
    reporting_period_start = models.DateField(blank=True, null=True)
    reporting_period_end = models.DateField(blank=True, null=True)
    create_date = models.DateTimeField(auto_now_add=True,
                                       blank=True,
                                       null=True)
    update_date = models.DateTimeField(auto_now=True, null=True)

    # Fields added to accomodate recipient_type of financial assistance records
    city_township_government = models.TextField(blank=True, null=True)
    special_district_government = models.TextField(blank=True, null=True)
    small_business = models.TextField(blank=True, null=True)
    small_business_description = models.TextField(blank=True, null=True)
    individual = models.TextField(blank=True, null=True)
    is_fpds = models.BooleanField(blank=False,
                                  default=False,
                                  verbose_name="Is FPDS")
    transaction_unique_id = models.TextField(
        blank=False, default="NONE", verbose_name="Transaction Unique ID")

    class Meta:
        managed = True
        db_table = "legal_entity"
        index_together = ("recipient_unique_id", "recipient_name",
                          "update_date")
Beispiel #37
0
 def test_deconstruct_with_size(self):
     field = ArrayField(models.IntegerField(), size=3)
     name, path, args, kwargs = field.deconstruct()
     new = ArrayField(*args, **kwargs)
     self.assertEqual(new.size, field.size)
Beispiel #38
0
 def test_with_size(self):
     field = ArrayField(models.IntegerField(), size=3)
     field.clean([1, 2, 3], None)
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean([1, 2, 3, 4], None)
     self.assertEqual(cm.exception.messages[0], 'List contains 4 items, it should contain no more than 3.')
Beispiel #39
0
class Cart(models.Model):
    shopkeeper = models.ForeignKey(User, on_delete=models.CASCADE)
    items = ArrayField(ArrayField(models.IntegerField(blank=True), null=True),
                       size=500,
                       blank=True,
                       default=list([]))
Beispiel #40
0
class RackReservation(PrimaryModel):
    """
    One or more reserved units within a Rack.
    """

    rack = models.ForeignKey(to="dcim.Rack", on_delete=models.CASCADE, related_name="reservations")
    units = ArrayField(base_field=models.PositiveSmallIntegerField())
    tenant = models.ForeignKey(
        to="tenancy.Tenant",
        on_delete=models.PROTECT,
        related_name="rackreservations",
        blank=True,
        null=True,
    )
    user = models.ForeignKey(to=User, on_delete=models.PROTECT)
    description = models.CharField(max_length=200)

    csv_headers = [
        "site",
        "rack_group",
        "rack",
        "units",
        "tenant",
        "user",
        "description",
    ]

    class Meta:
        ordering = ["created"]

    def __str__(self):
        return "Reservation for rack {}".format(self.rack)

    def get_absolute_url(self):
        return reverse("dcim:rackreservation", args=[self.pk])

    def clean(self):
        super().clean()

        if hasattr(self, "rack") and self.units:

            # Validate that all specified units exist in the Rack.
            invalid_units = [u for u in self.units if u not in self.rack.units]
            if invalid_units:
                raise ValidationError(
                    {
                        "units": "Invalid unit(s) for {}U rack: {}".format(
                            self.rack.u_height,
                            ", ".join([str(u) for u in invalid_units]),
                        ),
                    }
                )

            # Check that none of the units has already been reserved for this Rack.
            reserved_units = []
            for resv in self.rack.reservations.exclude(pk=self.pk):
                reserved_units += resv.units
            conflicting_units = [u for u in self.units if u in reserved_units]
            if conflicting_units:
                raise ValidationError(
                    {
                        "units": "The following units have already been reserved: {}".format(
                            ", ".join([str(u) for u in conflicting_units]),
                        )
                    }
                )

    def to_csv(self):
        return (
            self.rack.site.name,
            self.rack.group if self.rack.group else None,
            self.rack.name,
            ",".join([str(u) for u in self.units]),
            self.tenant.name if self.tenant else None,
            self.user.username,
            self.description,
        )

    @property
    def unit_list(self):
        return array_to_string(self.units)
Beispiel #41
0
 def test_blank_true(self):
     field = ArrayField(models.IntegerField(blank=True, null=True))
     # This should not raise a validation error
     field.clean([1, None], None)
Beispiel #42
0
class UserStory(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin,
                DueDateMixin, models.Model):
    ref = models.BigIntegerField(db_index=True,
                                 null=True,
                                 blank=True,
                                 default=None,
                                 verbose_name=_("ref"))
    milestone = models.ForeignKey("milestones.Milestone",
                                  null=True,
                                  blank=True,
                                  default=None,
                                  related_name="user_stories",
                                  on_delete=models.SET_NULL,
                                  verbose_name=_("milestone"))
    project = models.ForeignKey("projects.Project",
                                null=False,
                                blank=False,
                                related_name="user_stories",
                                verbose_name=_("project"))
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              null=True,
                              blank=True,
                              related_name="owned_user_stories",
                              verbose_name=_("owner"),
                              on_delete=models.SET_NULL)
    status = models.ForeignKey("projects.UserStoryStatus",
                               null=True,
                               blank=True,
                               related_name="user_stories",
                               verbose_name=_("status"),
                               on_delete=models.SET_NULL)
    is_closed = models.BooleanField(default=False)
    points = models.ManyToManyField("projects.Points",
                                    blank=False,
                                    related_name="userstories",
                                    through="RolePoints",
                                    verbose_name=_("points"))

    backlog_order = models.BigIntegerField(null=False,
                                           blank=False,
                                           default=timestamp_ms,
                                           verbose_name=_("backlog order"))
    sprint_order = models.BigIntegerField(null=False,
                                          blank=False,
                                          default=timestamp_ms,
                                          verbose_name=_("sprint order"))
    kanban_order = models.BigIntegerField(null=False,
                                          blank=False,
                                          default=timestamp_ms,
                                          verbose_name=_("kanban order"))

    created_date = models.DateTimeField(null=False,
                                        blank=False,
                                        verbose_name=_("created date"),
                                        default=timezone.now)
    modified_date = models.DateTimeField(null=False,
                                         blank=False,
                                         verbose_name=_("modified date"))
    finish_date = models.DateTimeField(null=True,
                                       blank=True,
                                       verbose_name=_("finish date"))
    subject = models.TextField(null=False,
                               blank=False,
                               verbose_name=_("subject"))
    description = models.TextField(null=False,
                                   blank=True,
                                   verbose_name=_("description"))
    assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL,
                                    blank=True,
                                    null=True,
                                    default=None,
                                    related_name="userstories_assigned_to_me",
                                    verbose_name=_("assigned to"))
    assigned_users = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        blank=True,
        default=None,
        related_name="assigned_userstories",
        verbose_name=_("assigned users"))
    client_requirement = models.BooleanField(
        default=False,
        null=False,
        blank=True,
        verbose_name=_("is client requirement"))
    team_requirement = models.BooleanField(
        default=False,
        null=False,
        blank=True,
        verbose_name=_("is team requirement"))
    attachments = GenericRelation("attachments.Attachment")
    generated_from_issue = models.ForeignKey(
        "issues.Issue",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="generated_user_stories",
        verbose_name=_("generated from issue"))
    external_reference = ArrayField(models.TextField(null=False, blank=False),
                                    null=True,
                                    blank=True,
                                    default=None,
                                    verbose_name=_("external reference"))

    tribe_gig = PickledObjectField(null=True,
                                   blank=True,
                                   default=None,
                                   verbose_name="taiga tribe gig")

    _importing = None

    class Meta:
        verbose_name = "user story"
        verbose_name_plural = "user stories"
        ordering = ["project", "backlog_order", "ref"]

    def save(self, *args, **kwargs):
        if not self._importing or not self.modified_date:
            self.modified_date = timezone.now()

        if not self.status:
            self.status = self.project.default_us_status

        super().save(*args, **kwargs)

        if not self.role_points.all():
            for role in self.project.roles.all():
                RolePoints.objects.create(role=role,
                                          points=self.project.default_points,
                                          user_story=self)

    def __str__(self):
        return "({1}) {0}".format(self.ref, self.subject)

    def __repr__(self):
        return "<UserStory %s>" % (self.id)

    def get_role_points(self):
        return self.role_points

    def get_total_points(self):
        not_null_role_points = [
            rp.points.value for rp in self.role_points.all()
            if rp.points.value is not None
        ]

        #If we only have None values the sum should be None
        if not not_null_role_points:
            return None

        return sum(not_null_role_points)
Beispiel #43
0
class Labeled(models.Model):
    id = models.IntegerField(help_text='labeling id',
                             null=False,
                             db_index=True,
                             primary_key=True)
    date = models.DateTimeField(help_text='date of observations',
                                null=False,
                                db_index=True)
    night = models.IntegerField(
        help_text='night of observation (YYYYMMDD, UT)',
        null=False,
        db_index=True,
        default=0)
    filearchivepath = models.TextField(
        help_text='thumbnail filename and archive path',
        null=False,
        db_index=False,
        default='')
    moonalt = models.FloatField(help_text='altitude of the Moon',
                                null=False,
                                db_index=True,
                                default=-99)
    sunalt = models.FloatField(help_text='altitude of the Sun',
                               null=False,
                               db_index=True,
                               default=-99)
    moonphase = models.FloatField(help_text='illumination of the Moon',
                                  null=False,
                                  db_index=True,
                                  default=-1)
    srcdens = ArrayField(models.FloatField(
        help_text='source density per subregion',
        null=False,
        db_index=False,
        default=-1),
                         null=True)
    bkgmean = ArrayField(models.FloatField(
        help_text='background mean value per subregion',
        null=False,
        db_index=False,
        default=-1),
                         null=True)
    bkgmedian = ArrayField(models.FloatField(
        help_text='background median value per subregion',
        null=False,
        db_index=False,
        default=-1),
                           null=True)
    bkgstd = ArrayField(models.FloatField(
        help_text='background standard deviation per subregion',
        null=False,
        db_index=False,
        default=-1),
                        null=True)
    srcdens_3min = ArrayField(models.FloatField(
        help_text='source density per subregion',
        null=False,
        db_index=False,
        default=-1),
                              null=True)
    bkgmean_3min = ArrayField(models.FloatField(
        help_text='background mean value per subregion',
        null=False,
        db_index=False,
        default=-1),
                              null=True)
    bkgmedian_3min = ArrayField(models.FloatField(
        help_text='background median value per subregion',
        null=False,
        db_index=False,
        default=-1),
                                null=True)
    bkgstd_3min = ArrayField(models.FloatField(
        help_text='background standard deviation per subregion',
        null=False,
        db_index=False,
        default=-1),
                             null=True)
    srcdens_15min = ArrayField(models.FloatField(
        help_text='source density per subregion',
        null=False,
        db_index=False,
        default=-1),
                               null=True)
    bkgmean_15min = ArrayField(models.FloatField(
        help_text='background mean value per subregion',
        null=False,
        db_index=False,
        default=-1),
                               null=True)
    bkgmedian_15min = ArrayField(models.FloatField(
        help_text='background median value per subregion',
        null=False,
        db_index=False,
        default=-1),
                                 null=True)
    bkgstd_15min = ArrayField(models.FloatField(
        help_text='background standard deviation per subregion',
        null=False,
        db_index=False,
        default=-1),
                              null=True)
    cloudy = ArrayField(models.BooleanField(
        help_text='indicates presence of clouds per subregion',
        null=False,
        db_index=False,
        default=False),
                        null=True)
    labeled_by = models.GenericIPAddressField(
        help_text='IP address of labeler', null=True, db_index=False)
    timestamp = models.DateTimeField(default=timezone.now,
                                     help_text='time of ingestion',
                                     null=False,
                                     db_index=False)

    class Meta:
        get_latest_by = 'date'
Beispiel #44
0
class Permission(models.Model):
    """
    Model describes field-level permissions.
    Main idea is to provide different set of readable/writable fields in dependency from current context.
    User roles and target state are defined in conditions, so we don't need to strongly determine user role.
    Then can be combined to grant more privileges for user in special cases.
    """

    PERMISSIONS = Choices(
        ('view', 'View'),
        ('edit', 'Edit'),
        ('action', 'Action'),
    )

    TYPES = Choices(
        ('allow', 'Allow'),
        ('disallow', 'Disallow'),
    )

    permission = models.CharField(max_length=10, choices=PERMISSIONS)
    permission_type = models.CharField(max_length=10,
                                       choices=TYPES,
                                       default=TYPES.allow)
    target = models.CharField(max_length=100)
    condition = ArrayField(models.CharField(max_length=100),
                           default=[],
                           blank=True)

    objects = PermissionQuerySet.as_manager()

    def __str__(self):
        return '{} permission to {} {} at {}'.format(
            self.permission_type.title(),
            self.permission,
            self.target,
            self.condition,
        )

    @staticmethod
    def get_target(model, field):
        if hasattr(field, 'name'):
            field = field.name
        elif hasattr(field, 'field_name'):
            field = field.field_name

        return '.'.join([model._meta.app_label, model._meta.model_name, field])

    @staticmethod
    def parse_target(target):
        app_label, model_name, field = target.split('.')
        model = apps.get_model(app_label, model_name)
        return model, field

    @classmethod
    def apply_permissions(cls, permissions, targets, kind):
        """
        apply permissions to targets
        :param permissions:
        :param targets:
        :param kind:
        :return:
        """
        permissions = list(permissions)

        i = 0
        children_map = dict()
        while i < len(permissions):
            perm = permissions[i]

            model, field_name = Permission.parse_target(perm.target)
            if model in children_map:
                children = children_map[model]
            else:
                children = collect_child_models(model, levels=1)
                children_map[model] = children

            # apply permissions to childs, in case of inheritance
            imaginary_permissions = [
                Permission(permission=perm.permission,
                           permission_type=perm.permission_type,
                           condition=perm.condition,
                           target=Permission.get_target(child, field_name))
                for child in children
            ]

            # permissions can be defined both for children and parent, so we need to priority
            # children permissions from automatically generated parent-based permissions.
            perm.image_level = getattr(perm, 'image_level', 0)
            for imaginary_perm in imaginary_permissions:
                imaginary_perm.image_level = perm.image_level + 1

            permissions.extend(imaginary_permissions)

            i += 1

        # order permissions in dependency from their level and complexity of condition
        permissions.sort(key=lambda perm: (perm.image_level, -len(
            perm.condition), '*' in perm.target))

        allowed_targets = []
        targets = set(targets)
        for perm in permissions:
            if kind == cls.PERMISSIONS.view and perm.permission_type == cls.TYPES.allow:
                # If you can edit field you can view it too.
                if perm.permission not in [
                        cls.PERMISSIONS.view, cls.PERMISSIONS.edit
                ]:
                    continue
            elif perm.permission != kind:
                continue

            if perm.target[-1] == '*':
                affected_targets = set(
                    filter(lambda target: target.startswith(perm.target[:-1]),
                           targets))
            else:
                affected_targets = {perm.target}

            if not affected_targets:
                continue

            if perm.permission_type == cls.TYPES.allow and affected_targets & targets:
                allowed_targets.extend(affected_targets)

            targets -= affected_targets

        return allowed_targets
Beispiel #45
0
 def test_model_field_formfield(self):
     model_field = ArrayField(models.CharField(max_length=27))
     form_field = model_field.formfield()
     self.assertIsInstance(form_field, SimpleArrayField)
     self.assertIsInstance(form_field.base_field, forms.CharField)
     self.assertEqual(form_field.base_field.max_length, 27)
Beispiel #46
0
class Category(models.Model):

    class Meta(object):
        verbose_name = "Catégorie"
        verbose_name_plural = "Catégories"

    slug = models.SlugField(
        verbose_name="Slug",
        max_length=100,
        blank=True,
        unique=True,
        db_index=True,
        )

    ckan_id = models.UUIDField(
        verbose_name="Identifiant CKAN",
        editable=False,
        db_index=True,
        default=uuid.uuid4,
        )

    name = models.CharField(  # TODO title->TextField
        verbose_name="Nom",
        max_length=100,
        )

    alternate_titles = ArrayField(
        models.TextField(),
        verbose_name="Autres titres",
        blank=True,
        null=True,
        size=None,
        )

    description = models.CharField(
        verbose_name="Description",
        max_length=1024,
        )

    iso_topic = models.CharField(
        verbose_name="Thème ISO",
        max_length=100,
        null=True,
        blank=True,
        choices=ISO_TOPIC_CHOICES,
        )

    picto = models.ImageField(
        verbose_name="Pictogramme",
        upload_to='logos/',
        null=True,
        blank=True,
        )

    def __str__(self):
        return self.name

    def sync_ckan(self):
        if self.pk:
            CkanHandler.update_group(self)
        else:
            CkanHandler.add_group(self)

    def clean(self):
        self.slug = slugify(self.name)
        try:
            self.sync_ckan()
        except Exception as e:
            raise ValidationError(e.__str__())
Beispiel #47
0
 def test_model_field_choices(self):
     model_field = ArrayField(models.IntegerField(choices=((1, 'A'), (2, 'B'))))
     form_field = model_field.formfield()
     self.assertEqual(form_field.clean('1,2'), [1, 2])
Beispiel #48
0
class User(models.Model, ModelDiffMixin):
    MEMBERSHIP_PLATFORM_DIRECT = "direct"
    MEMBERSHIP_PLATFORM_PATREON = "patreon"
    MEMBERSHIP_PLATFORMS = [
        (MEMBERSHIP_PLATFORM_DIRECT, "Direct"),
        (MEMBERSHIP_PLATFORM_PATREON, "Patreon"),
    ]

    EMAIL_DIGEST_TYPE_NOPE = "nope"
    EMAIL_DIGEST_TYPE_DAILY = "daily"
    EMAIL_DIGEST_TYPE_WEEKLY = "weekly"
    EMAIL_DIGEST_TYPES = [
        (EMAIL_DIGEST_TYPE_NOPE, "Nothing"),
        (EMAIL_DIGEST_TYPE_DAILY, "Daily"),
        (EMAIL_DIGEST_TYPE_WEEKLY, "Weekly"),
    ]

    ROLE_CURATOR = "curator"
    ROLE_MODERATOR = "moderator"
    ROLE_GOD = "god"
    ROLES = [(ROLE_CURATOR, "Куратор"), (ROLE_MODERATOR, "Модератор"),
             (ROLE_GOD, "Бог")]

    MODERATION_STATUS_INTRO = "intro"
    MODERATION_STATUS_ON_REVIEW = "on_review"
    MODERATION_STATUS_REJECTED = "rejected"
    MODERATION_STATUS_APPROVED = "approved"
    MODERATION_STATUSES = [
        (MODERATION_STATUS_INTRO, MODERATION_STATUS_INTRO),
        (MODERATION_STATUS_ON_REVIEW, MODERATION_STATUS_ON_REVIEW),
        (MODERATION_STATUS_REJECTED, MODERATION_STATUS_REJECTED),
        (MODERATION_STATUS_APPROVED, MODERATION_STATUS_APPROVED),
    ]

    DEFAULT_AVATAR = "https://i.vas3k.club/v.png"

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    slug = models.CharField(max_length=32, unique=True)
    card_number = models.IntegerField(default=0)

    email = models.EmailField(unique=True)
    full_name = models.CharField(max_length=128, null=False)
    avatar = models.URLField(null=True, blank=True)
    secret_hash = models.CharField(max_length=16, db_index=True)

    company = models.TextField(null=True)
    position = models.TextField(null=True)
    city = models.CharField(max_length=128, null=True)
    country = models.CharField(max_length=128, null=True)
    geo = models.ForeignKey(Geo, on_delete=models.SET_NULL, null=True)
    bio = models.TextField(null=True)
    contact = models.CharField(max_length=256, null=True)
    hat = JSONField(null=True)

    balance = models.IntegerField(default=0)
    upvotes = models.IntegerField(default=0)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    last_activity_at = models.DateTimeField(auto_now=True)

    membership_started_at = models.DateTimeField(null=False)
    membership_expires_at = models.DateTimeField(null=False)
    membership_platform_type = models.CharField(
        max_length=128,
        choices=MEMBERSHIP_PLATFORMS,
        default=MEMBERSHIP_PLATFORM_PATREON,
        null=False)
    patreon_id = models.CharField(max_length=128, null=True, unique=True)
    membership_platform_data = JSONField(null=True)

    email_digest_type = models.CharField(max_length=16,
                                         choices=EMAIL_DIGEST_TYPES,
                                         default=EMAIL_DIGEST_TYPE_WEEKLY,
                                         null=False)

    telegram_id = models.CharField(max_length=128, null=True)
    telegram_data = JSONField(null=True)

    is_email_verified = models.BooleanField(default=False)
    is_email_unsubscribed = models.BooleanField(default=False)
    is_banned_until = models.DateTimeField(null=True)

    moderation_status = models.CharField(max_length=32,
                                         choices=MODERATION_STATUSES,
                                         default=MODERATION_STATUS_INTRO,
                                         null=False,
                                         db_index=True)

    roles = ArrayField(models.CharField(max_length=32, choices=ROLES),
                       default=list,
                       null=False)

    class Meta:
        db_table = "users"

    def save(self, *args, **kwargs):
        if not self.secret_hash:
            self.secret_hash = random_hash(length=16)

        if not self.slug:
            self.slug = generate_unique_slug(User,
                                             self.full_name,
                                             separator="")

        self.updated_at = datetime.utcnow()
        return super().save(*args, **kwargs)

    def to_dict(self):
        return {
            "slug":
            self.slug,
            "full_name":
            self.full_name,
            "avatar":
            self.avatar,
            "moderation_status":
            self.moderation_status,
            "payment_status":
            "active"
            if self.membership_expires_at >= datetime.utcnow() else "inactive",
        }

    def update_last_activity(self):
        now = datetime.utcnow()
        if self.last_activity_at < now - timedelta(minutes=5):
            return User.objects.filter(id=self.id).update(last_activity_at=now)

    def membership_days_left(self):
        return (self.membership_expires_at -
                datetime.utcnow()).total_seconds() // 60 // 60 / 24

    def membership_years_left(self):
        return self.membership_days_left() / 365

    def increment_vote_count(self):
        return User.objects.filter(id=self.id).update(upvotes=F("upvotes") + 1)

    def decrement_vote_count(self):
        return User.objects.filter(id=self.id).update(upvotes=F("upvotes") - 1)

    def get_avatar(self):
        return self.avatar or self.DEFAULT_AVATAR

    @property
    def is_banned(self):
        if self.is_god:
            return False
        return self.is_banned_until and self.is_banned_until > datetime.utcnow(
        )

    @property
    def is_god(self):
        return self.roles and self.ROLE_GOD in self.roles

    @property
    def is_moderator(self):
        return (self.roles
                and self.ROLE_MODERATOR in self.roles) or self.is_god

    @property
    def is_club_member(self):
        return self.moderation_status == User.MODERATION_STATUS_APPROVED and not self.is_banned

    @property
    def is_paid_member(self):
        return self.is_club_member and self.membership_expires_at >= datetime.utcnow(
        )

    @property
    def secret_auth_code(self):
        return f"{self.email}|-{self.secret_hash}"

    @classmethod
    def registered_members(cls):
        return cls.objects.filter(
            moderation_status=User.MODERATION_STATUS_APPROVED)