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.')
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.')
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')
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.' )
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})
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})
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})
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"
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
class EventReceiveUser(BaseModel): user_id = ArrayField(models.IntegerField()) class Meta: db_table = 'event_receive_users'
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)
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()
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
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
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
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)
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
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)
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) }
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)
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']
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)
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='')
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))
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()
class EventReceiveGroup(BaseModel): group_id = ArrayField(models.IntegerField()) class Meta: db_table = 'event_receive_groups'
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)
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
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')
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
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
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."))
class IntegerRangeArrayModel(PostgreSQLModel): field = ArrayField(IntegerRangeField())
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')
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")
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)
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.')
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([]))
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)
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)
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)
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'
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
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)
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__())
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])
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)