class Migration(migrations.Migration): dependencies = [ ('siteapp', '0055_auto_20220330_1629'), ] operations = [ migrations.AlterField( model_name='appointment', name='party', field=auto_prefetch.ForeignKey( blank=True, help_text='The Party appointed to the Role.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parties', to='siteapp.party'), ), migrations.AlterField( model_name='appointment', name='role', field=auto_prefetch.ForeignKey( blank=True, help_text='The Role being appointed.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='roles', to='siteapp.role'), ), ]
class BaseFactAbstractModel(auto_prefetch.Model): """BaseFactAbstractModel A Base model for Facts""" title = models.CharField(max_length=200, help_text="Fact title") snippet = models.CharField(max_length=200, blank=True, default="", help_text="Short Fact description") description = models.TextField(blank=True, default="", help_text="Fact description") fact = models.TextField(default="") slug = models.SlugField(unique=True, default="", max_length=200, help_text="Fact slug") created_date = models.DateTimeField(default=timezone.now, help_text="Creation date") mod_date = models.DateTimeField(auto_now=True, help_text="Last modification") pub_date = models.DateTimeField(blank=True, null=True, help_text="Publication date") rnd_choice = models.IntegerField( default=0, help_text="How many times the Fact has been randomly selected") link = auto_prefetch.ForeignKey(Links, on_delete=models.CASCADE, null=True, blank=True) shown = models.BooleanField(default=True, help_text="Is it shown") priority = models.PositiveIntegerField(default=0) # Metadata about the fact site = auto_prefetch.ForeignKey(Site, default=1, on_delete=models.CASCADE) class Meta(auto_prefetch.Model.Meta): abstract = True def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.title) return super().save(*args, **kwargs) def save_without_historical_record(self, *args, **kwargs): self.skip_history_when_saving = True try: ret = self.save(*args, **kwargs) finally: del self.skip_history_when_saving return ret def rnd_chosen(self): self.rnd_choice += 1 self.save_without_historical_record(update_fields=["rnd_choice"])
class SystemAssessmentResult(auto_prefetch.Model): name = models.CharField(max_length=250, help_text="Name of the system assessment result", unique=False, blank=False, null=False) description = models.CharField( max_length=255, help_text="Brief description of the system assessment result", unique=False, blank=True, null=True) created = models.DateTimeField(auto_now_add=True, db_index=True) updated = models.DateTimeField(auto_now=True, db_index=True) uuid = models.UUIDField( default=uuid.uuid4, editable=True, help_text= "A UUID (a unique identifier) for the system assessment result.") system = auto_prefetch.ForeignKey( 'System', related_name='system_assessment_result', on_delete=models.CASCADE, blank=True, null=True, help_text="The system associated with the system assessment result") deployment = auto_prefetch.ForeignKey( Deployment, related_name="assessment_results", unique=False, blank=True, null=True, on_delete=models.SET_NULL, help_text="The deployment associated with the assessment result.") assessment_results = JSONField( blank=True, null=True, help_text= "JSON object representing the system assessment results associated with a deployment." ) history = HistoricalRecords(cascade_delete_history=True) def __str__(self): return "<SystemAssesmentResult %s id=%d>" % (self.system, self.id) def __repr__(self): # For debugging. return "<SystemAssesmentResult %s id=%d>" % (self.system, self.id)
class Deployment(auto_prefetch.Model): name = models.CharField(max_length=250, help_text="Name of the deployment", unique=False, blank=False, null=False) description = models.CharField(max_length=255, help_text="Brief description of the deployment", unique=False, blank=False, null=False) created = models.DateTimeField(auto_now_add=True, db_index=True) updated = models.DateTimeField(auto_now=True, db_index=True) uuid = models.UUIDField(default=uuid.uuid4, editable=True, help_text="A UUID (a unique identifier) for the deployment.") system = auto_prefetch.ForeignKey('System', related_name='deployments', on_delete=models.CASCADE, blank=True, null=True, help_text="The system associated with the deployment") inventory_items = JSONField(blank=True, null=True, help_text="JSON object representing the inventory items in a deployment.") history = HistoricalRecords(cascade_delete_history=True) # Notes # # Retrieve System Deployment # from controls.models import * # s = System.objects.get(pk=11) # s.deployments.all() # # returns <QuerySet ['ac-2 id=1', 'ac-3 id=2', 'au-2 id=3']> # def __str__(self): return "'%s id=%d'" % (self.name, self.id) def __repr__(self): # For debugging. return "'%s id=%d'" % (self.name, self.id) def get_absolute_url(self): return "/systems/%d/deployments" % (self.system.id)
class Tag(MPTTModel, auto_prefetch.Model): text = models.CharField(max_length=100) parent = auto_prefetch.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children') def __str__(self): return self.text def all_siblings_leaf(self, all_tags): """Return true if all siblings, including self, are leaf nodes. """ # siblings = self.get_siblings(include_self=True) if self.parent is None: siblings = [t for t in all_tags if t.parent is None] else: siblings = [t for t in all_tags if t.parent == self.parent] return all([s.is_leaf_node() for s in siblings]) class MPTTMeta: order_insertion_by = ['text'] class MyManager(TreeManager, auto_prefetch.Manager): pass objects = MyManager()
class Migration(migrations.Migration): dependencies = [ ('controls', '0061_fix_800_171_ids'), ] operations = [ migrations.CreateModel( name='StatementRemote', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('remote_type', models.CharField(blank=True, choices=[('ORIGIN', 'origin')], help_text='Remote type.', max_length=80, null=True)), ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, help_text='A UUID (a unique identifier) for this Statement.')), ('created', models.DateTimeField(auto_now_add=True, db_index=True)), ('updated', models.DateTimeField(auto_now=True, db_index=True)), ('import_record', auto_prefetch.ForeignKey(blank=True, help_text='The Import Record which created this record.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='import_record_statement_remotes', to='controls.importrecord')), ('remote_statement', models.ForeignKey(blank=True, help_text='Remote or parent Statement.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='descendents', to='controls.statement')), ('statement', models.ForeignKey(blank=True, help_text='Descendent or cloned Statement.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='remotes', to='controls.statement')), ], options={ 'abstract': False, 'base_manager_name': 'prefetch_manager', }, managers=[ ('objects', django.db.models.manager.Manager()), ('prefetch_manager', django.db.models.manager.Manager()), ], ), ]
class Endpoint(auto_prefetch.Model, BaseModel): integration = auto_prefetch.ForeignKey(Integration, related_name="endpoints", on_delete=models.CASCADE, help_text="Endpoint's Integration") endpoint_path = models.CharField(max_length=250, help_text="Path to the Endpoint", unique=False, blank=True, null=True) description = models.TextField( default="", help_text="Brief description of the endpoint", unique=False, blank=True, null=True) element_type = models.CharField(max_length=150, help_text="Component type", unique=False, blank=True, null=True) data = JSONField(blank=True, null=True, default=dict, help_text="JSON object representing the API results.") history = HistoricalRecords(cascade_delete_history=True) def __str__(self): return f"'{self.integration.name} {self.endpoint_path} id={self.id}'" def __repr__(self): return f"'{self.integration.name}{self.endpoint_path} id={self.id}'"
class Migration(migrations.Migration): initial = True dependencies = [] operations = [ migrations.CreateModel( name='Tag', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('text', models.CharField(max_length=100)), ('lft', models.PositiveIntegerField(editable=False)), ('rght', models.PositiveIntegerField(editable=False)), ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), ('level', models.PositiveIntegerField(editable=False)), ('parent', auto_prefetch.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='tags.Tag')), ], options={ 'abstract': False, }, ), ]
class Migration(migrations.Migration): dependencies = [ ('pricetype', '0002_auto_20210313_1042'), ('listings', '0012_auto_20210322_0800'), ] operations = [ migrations.AlterModelManagers( name='listing', managers=[ ('objects', django.db.models.manager.Manager()), ('prefetch_manager', django.db.models.manager.Manager()), ], ), migrations.AlterField( model_name='listing', name='pricetext', field=models.CharField(blank=True, max_length=100, null=True), ), migrations.AlterField( model_name='listing', name='pricetype', field=auto_prefetch.ForeignKey( null=True, on_delete=django.db.models.deletion.CASCADE, to='pricetype.pricetype'), ), ]
class CommonControl(auto_prefetch.Model): name = models.CharField(max_length=150, help_text="Name of the CommonControl", unique=False, blank=True, null=True) description = models.CharField( max_length=255, help_text="Brief description of the CommonControlProvider", unique=False) oscal_ctl_id = models.CharField( max_length=20, help_text="OSCAL formatted Control ID (e.g., au-2.3)", blank=True, null=True) legacy_imp_smt = models.TextField( help_text="Legacy large implementation statement", unique=False, blank=True, null=True, ) common_control_provider = auto_prefetch.ForeignKey( CommonControlProvider, on_delete=models.CASCADE) def __str__(self): return self.name
class MenuFooterLink(auto_prefetch.Model): VISIBILITY_CHOICES = [ ("D", "default"), ("NP", "needs_permission"), ("NS", "needs_staff"), ("NA", "needs_admin"), ] title = models.CharField(max_length=200, blank=True) rel_url = models.CharField(max_length=200, blank=True) url = models.URLField(blank=True) visibility = models.CharField( max_length=25, verbose_name="Visibility", choices=VISIBILITY_CHOICES, default="D", ) links = auto_prefetch.ForeignKey("settings_app.MenuFooter", on_delete=models.CASCADE, related_name="menu_footer_links") is_target_blank = models.BooleanField(default=False) class Meta: verbose_name_plural = "Menu Footer Links" def __str__(self): return self.title def get_rel_url(self): return "/" + self.rel_url
class ElementCommonControl(auto_prefetch.Model): element = auto_prefetch.ForeignKey(Element, related_name="common_controls", on_delete=models.CASCADE, help_text="The Element (e.g., System, Component, Host) to which common controls are associated.") common_control = auto_prefetch.ForeignKey(CommonControl, related_name="element_common_control", on_delete=models.CASCADE, help_text="The Common Control for this association.") oscal_ctl_id = models.CharField(max_length=20, help_text="OSCAL formatted Control ID (e.g., au-2.3)", blank=True, null=True) oscal_catalog_key = models.CharField(max_length=100, help_text="Catalog key from which catalog file can be derived (e.g., 'NIST_SP-800-53_rev4')", blank=True, null=True) created = models.DateTimeField(auto_now_add=True, db_index=True) updated = models.DateTimeField(auto_now=True, db_index=True) class Meta: unique_together = [('element', 'common_control', 'oscal_ctl_id', 'oscal_catalog_key')] def __str__(self): return f"'{self.element} {self.common_control} {self.oscal_ctl_id} id={self.id}'" def __repr__(self): # For debugging. return f"'{self.element} {self.common_control} {self.oscal_ctl_id} id={self.id}'"
class Choice(auto_prefetch.Model): question = auto_prefetch.ForeignKey(Question, on_delete=models.CASCADE, related_name="related_question") title = models.CharField(max_length=200) votes = models.IntegerField(default=0) def __str__(self): return self.title
class Migration(migrations.Migration): dependencies = [ ('siteapp', '0066_alter_project_tags'), ('controls', '0074_auto_20220614_1436'), ] operations = [ migrations.CreateModel( name='SystemEvent', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateTimeField(auto_now_add=True, db_index=True)), ('updated', models.DateTimeField(auto_now=True, db_index=True, null=True)), ('event_type', models.CharField(help_text='Event type', max_length=12)), ('description', models.CharField(help_text='Brief description of the event', max_length=255)), ('info', models.JSONField( blank=True, default=dict, help_text='JSON object detailed event information')), ('system', auto_prefetch.ForeignKey( blank=True, help_text='Events related to the system', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='events', to='controls.system')), ('tags', models.ManyToManyField(blank=True, related_name='systemevent', to='siteapp.Tag')), ], options={ 'abstract': False, 'base_manager_name': 'prefetch_manager', }, managers=[ ('objects', django.db.models.manager.Manager()), ('prefetch_manager', django.db.models.manager.Manager()), ], ), ]
class Migration(migrations.Migration): dependencies = [ ('controls', '0070_auto_20220418_1140'), ('siteapp', '0058_request'), ] operations = [ migrations.AlterField( model_name='request', name='requested_element', field=auto_prefetch.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='request', to='controls.element'), ), migrations.AlterField( model_name='request', name='system', field=auto_prefetch.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='request', to='controls.system'), ), migrations.AlterField( model_name='request', name='user', field=auto_prefetch.ForeignKey( blank=True, help_text='User creating the request.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='request', to=settings.AUTH_USER_MODEL), ), ]
class BaseLinkAbstractModel(auto_prefetch.Model): """ An abstract base class that any custom link models probably should subclass. """ # Content-object field content_type = auto_prefetch.ForeignKey( ContentType, verbose_name=_("content type"), related_name="content_type_set_for_%(class)s", on_delete=models.CASCADE, blank=True, null=True, ) object_pk = models.CharField(_("object ID"), db_index=True, max_length=64, blank=True, null=True) content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk") index = models.BooleanField(default=False) # Metadata about the link site = auto_prefetch.ForeignKey(Site, on_delete=models.CASCADE) class Meta(auto_prefetch.Model.Meta): """Meta Class for BaseLinkAbstractModel Model""" abstract = True def get_content_object_url(self): """Get a URL suitable for redirecting to the content object.""" return reverse("links:link-url-redirect", args=(self.content_type, self.object_pk))
class PostCatsLink(auto_prefetch.Model): """PostCatsLink Through Table Model A through table Model linking Post and Category Args: auto_prefetch ([type]): [description] Returns: PostCatsLink: postcatslink_set """ post = auto_prefetch.ForeignKey("blog.Post", on_delete=models.CASCADE) category = auto_prefetch.ForeignKey("blog.Category", on_delete=models.CASCADE) featured_cat = models.BooleanField(default=False) class Meta: """Meta class for PostCatsLink Through Table""" verbose_name_plural = "Post to Category Link" def __str__(self): return "%s - %s" % (self.post.title, self.category.title)
class Migration(migrations.Migration): dependencies = [ ('controls', '0053_auto_20210701_1133'), ('siteapp', '0049_user_default_portfolio'), ] operations = [ migrations.AddField( model_name='project', name='import_record', field=auto_prefetch.ForeignKey( blank=True, help_text='The Import Record which created this Project.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='import_record_projects', to='controls.importrecord'), ), ]
class Listing(auto_prefetch.Model): # pricetype choises pricetype = auto_prefetch.ForeignKey(Pricetype, null=True, on_delete=models.CASCADE) pricetext = models.CharField(max_length=100, blank=True, null=True ) buybuttontxt = models.TextField(blank=True, null=True) hasprice = models.BooleanField(blank=True, default=False, ) payment = models.BooleanField(blank=True, default=False, ) bid = models.BooleanField(blank=True, default=False, ) bidoptional = models.BooleanField(blank=True, default=False, ) # Listing description name = models.CharField(max_length=100, validators=[alphanumeric]) price = models.DecimalField(max_digits=6, decimal_places=2, null=True, default=0.00, blank=True) firstimage = models.ImageField(blank=True,) thumbnail = ImageSpecField(source='firstimage', processors={ResizeToFit(262,222)}, format='JPEG', options={'quality':80}) secondimage = models.ImageField(blank=True,) secondthumbnail = ImageSpecField(source='secondimage', processors={ResizeToFit(262,222)}, format='JPEG', options={'quality':80}) description = models.TextField(blank=True, null=True) # Other data category = TreeForeignKey('categorys.Category', related_name='category', on_delete=models.CASCADE) # Logistic pickup = models.BooleanField(blank=True, default=False, ) delivery = models.BooleanField(blank=True, default=False, ) deliverycost = models.DecimalField(max_digits=6, decimal_places=2, null=True, default=0.00, blank=True) # Other data author = UserForeignKey(auto_user_add=True, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) slug = AutoSlugField(populate_from='name', validators=[alphanumeric]) class Meta: ordering = ('-created_at',) def __str__(self): return self.name def get_absolute_url(self): url = reverse('listing', kwargs={'pk': self.pk, 'slug': self.get_slug()}) return url def make_thumbnail(source, width, height, generator_id=None): if not os.path.exist(source): return None
class Project(BasePortfolioAbstractModel): """Model for Project""" featured = models.BooleanField(default=False) history = HistoricalRecords() website = auto_prefetch.ForeignKey( "portfolio.Website", on_delete=models.CASCADE, related_name="websites", null=True, blank=True, ) repository = auto_prefetch.ForeignKey( "portfolio.Repository", on_delete=models.DO_NOTHING, related_name="repositories", null=True, blank=True, ) technology = auto_prefetch.ForeignKey( "portfolio.Technology", on_delete=models.DO_NOTHING, related_name="technologies", null=True, blank=True, ) class Meta(BasePortfolioAbstractModel.Meta): """Meta class for Project Model Class""" ordering = ["pk"] def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.title) return super().save(*args, **kwargs) def get_absolute_url(self): return reverse("portfolio:project_detail", kwargs={"slug": self.slug}) def get_absolute_update_url(self): return reverse("portfolio:project_edit", kwargs={"slug": self.slug}) def get_absolute_delete_url(self): return reverse("portfolio:project_delete", kwargs={"slug": self.slug}) def get_absolute_admin_update_url(self): return reverse("admin:portfolio_project_change", kwargs={"object_id": self.pk}) @property def get_sub_projects(self): sub_projects = self.sub_project.filter(is_removed=False) return sub_projects def remove(self): self.is_removed = True self.save() def get_index_view_url(self): content_type = ContentType.objects.get_for_model(self.__class__) return reverse("%s:%s_list" % (content_type.app_label, content_type.model))
class MixedField(models.Model): friend = auto_prefetch.ForeignKey(Friend, null=True, on_delete=models.CASCADE) associates = models.ManyToManyField(Associate)
class Prefetch2(auto_prefetch.Model): other = auto_prefetch.ForeignKey(Prefetch, null=True, on_delete=models.CASCADE)
class Category(RulesModelMixin, auto_prefetch.Model, metaclass=RulesModelBase): """Category model A model for Category Args: RulesModelMixin ([type]): [description] auto_prefetch ([type]): [description] metaclass ([type], optional): [description]. Defaults to RulesModelBase. Returns: Category: A model for Category """ parent = auto_prefetch.ForeignKey( "self", on_delete=models.CASCADE, related_name="category_children", null=True, blank=True, ) title = models.CharField(max_length=200, help_text="Category title") suffix = models.CharField(max_length=200, help_text="Category suffix", blank=True, default="") description = models.TextField(blank=True, help_text="Category description") slug = models.SlugField(unique=True, default="", max_length=200, help_text="Category slug") created_date = models.DateTimeField(default=timezone.now, help_text="Creation date") mod_date = models.DateTimeField(auto_now=True, help_text="Last modification") withdrawn = models.BooleanField(default=False, help_text="Is Category withdrawn") is_removed = models.BooleanField("is removed", default=False, db_index=True, help_text=("Soft delete")) needs_reviewing = models.BooleanField(default=False, help_text=("Needs reviewing")) history = HistoricalRecords() objects: CategoryManager = CategoryManager() class Meta: """Meta class for Category Model""" ordering = ["pk"] verbose_name_plural = "Categories" rules_permissions = { "add": rules.is_superuser, "update": rules.is_superuser, } def __str__(self): return self.full_title def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.full_title) return super().save(*args, **kwargs) def get_absolute_url(self): return reverse("blog:post_category_list", kwargs={"slug": self.slug}) def get_absolute_update_url(self): return reverse("blog:category_edit", kwargs={"slug": self.slug}) def get_absolute_needs_review_url(self): return reverse("blog:category_needs_review", kwargs={"slug": self.slug}) def get_absolute_delete_url(self): return reverse("blog:category_remove", kwargs={"slug": self.slug}) def get_absolute_admin_update_url(self): return reverse("admin:blog_category_change", kwargs={"object_id": self.pk}) def needs_review(self): self.needs_reviewing = True self.save() def remove(self): self.is_removed = True self.save() @property def get_post_count_in_category(self): return self.postcatslink_set.filter( post__pub_date__lte=timezone.now(), post__withdrawn=False, post__is_removed=False, ).count() @property def get_superuser_post_count_in_category(self): return self.postcatslink_set.filter(post__is_removed=False).count() @property def get_superuser_percent_of_posts(self) -> str: percentage = self.get_superuser_post_count_in_category / Post.objects.filter( is_removed=False).count() * 100 return f"{round(percentage, 2)}%" @property def get_percent_of_posts(self) -> str: percentage = (self.get_post_count_in_category / Post.objects.filter( pub_date__lte=timezone.now(), withdrawn=False, is_removed=False).count() * 100) return f"{round(percentage, 2)}%" @property def full_title(self) -> str: fulltitle = "" if self.suffix: fulltitle = self.title + " " + self.suffix elif not self.suffix and not self.parent: fulltitle = self.title elif not self.suffix and self.parent and self.parent.suffix: fulltitle = self.title + " " + self.parent.suffix else: fulltitle = self.title return fulltitle def get_index_view_url(self): content_type = ContentType.objects.get_for_model(self.__class__) return reverse("%s:%s_list" % (content_type.app_label, content_type.model))
class Statement(auto_prefetch.Model): sid = models.CharField( max_length=100, help_text="Statement identifier such as OSCAL formatted Control ID", unique=False, blank=True, null=True) sid_class = models.CharField( max_length=200, help_text= "Statement identifier 'class' such as 'NIST_SP-800-53_rev4' or other OSCAL catalog name Control ID.", unique=False, blank=True, null=True) pid = models.CharField( max_length=20, help_text= "Statement part identifier such as 'h' or 'h.1' or other part key", unique=False, blank=True, null=True) body = models.TextField(help_text="The statement itself", unique=False, blank=True, null=True) statement_type = models.CharField(max_length=150, help_text="Statement type.", unique=False, blank=True, null=True) remarks = models.TextField(help_text="Remarks about the statement.", unique=False, blank=True, null=True) status = models.CharField(max_length=100, help_text="The status of the statement.", unique=False, blank=True, null=True) version = models.CharField(max_length=20, help_text="Optional version number.", unique=False, blank=True, null=True) created = models.DateTimeField(auto_now_add=True, db_index=True) updated = models.DateTimeField(auto_now=True, db_index=True) parent = auto_prefetch.ForeignKey('self', help_text="Parent statement", related_name="children", on_delete=models.SET_NULL, blank=True, null=True) prototype = auto_prefetch.ForeignKey('self', help_text="Prototype statement", related_name="instances", on_delete=models.SET_NULL, blank=True, null=True) producer_element = auto_prefetch.ForeignKey( 'Element', related_name='statements_produced', on_delete=models.CASCADE, blank=True, null=True, help_text="The element producing this statement.") consumer_element = auto_prefetch.ForeignKey( 'Element', related_name='statements_consumed', on_delete=models.CASCADE, blank=True, null=True, help_text="The element the statement is about.") mentioned_elements = models.ManyToManyField( 'Element', related_name='statements_mentioning', blank=True, help_text= "All elements mentioned in a statement; elements with a first degree relationship to the statement." ) uuid = models.UUIDField( default=uuid.uuid4, editable=False, help_text="A UUID (a unique identifier) for this Statement.") import_record = auto_prefetch.ForeignKey( ImportRecord, related_name="import_record_statements", on_delete=models.CASCADE, unique=False, blank=True, null=True, help_text="The Import Record which created this Statement.") history = HistoricalRecords(cascade_delete_history=True) class Meta: indexes = [ models.Index(fields=['producer_element'], name='producer_element_idx'), ] permissions = [ ('can_grant_smt_owner_permission', 'Grant a user statement owner permission'), ] ordering = ['producer_element__name', 'sid'] def __str__(self): return "'%s %s %s %s %s'" % (self.statement_type, self.sid, self.pid, self.sid_class, self.id) def __repr__(self): # For debugging. return "'%s %s %s %s %s'" % (self.statement_type, self.sid, self.pid, self.sid_class, self.id) @cached_property def producer_element_name(self): return self.producer_element.name @property def catalog_control(self): """Return the control content from the catalog""" # Get instance of the control catalog catalog = Catalog.GetInstance(catalog_key=self.sid_class) # Look up control by ID return catalog.get_control_by_id(self.sid) @property def catalog_control_as_dict(self): """Return the control content from the catalog""" # Get instance of the control catalog catalog = Catalog.GetInstance(catalog_key=self.sid_class) catalog_control_dict = catalog.get_flattened_controls_all_as_dict() # Look up control by ID return catalog_control_dict[self.sid] def create_prototype(self): """Creates a prototype statement from an existing statement and prototype object""" if self.prototype is not None: # Prototype already exists for statement return self.prototype # check if prototype content is the same, report error if not, or overwrite if permission approved prototype = deepcopy(self) prototype.statement_type = "control_implementation_prototype" prototype.consumer_element_id = None prototype.id = None prototype.save() # Set prototype attribute on the instances to newly created prototype self.prototype = prototype self.save() return self.prototype def create_instance_from_prototype(self, consumer_element_id): """Creates a control_implementation statement instance for a system's root_element from an existing control implementation prototype statement""" # TODO: Check statement is a prototype # System already has instance of the control_implementation statement # TODO: write check for this logic # Get all statements for consumer element so we can identify smts_existing = Statement.objects.filter( consumer_element__id=consumer_element_id, statement_type="control_implementation").select_related( 'prototype') # Get prototype ids for all consumer element statements smts_existing_prototype_ids = [ smt.prototype.id for smt in smts_existing ] if self.id is smts_existing_prototype_ids: return self.prototype # # TODO: # # check if prototype content is the same, report error if not, or overwrite if permission approved instance = deepcopy(self) instance.statement_type = "control_implementation" instance.consumer_element_id = consumer_element_id instance.id = None # Set prototype attribute to newly created instance instance.prototype = self instance.save() return instance @property def prototype_synched(self): """Returns one of STATEMENT_SYNCHED, STATEMENT_NOT_SYNCHED, STATEMENT_ORPHANED for control_implementations""" if self.statement_type == "control_implementation": if self.prototype: if self.body == self.prototype.body: return STATEMENT_SYNCHED else: return STATEMENT_NOT_SYNCHED else: return STATEMENT_ORPHANED else: return STATEMENT_NOT_SYNCHED @property def diff_prototype_main(self): """Generate a diff of statement of type `control_implementation` and its prototype""" if self.statement_type != 'control_implementation': # TODO: Should we return None or raise error because statement is not of type control_implementation? return None if self.prototype is None: # TODO: Should we return None or raise error because statement does not have a prototype? return None dmp = dmp_module.diff_match_patch() diff = dmp.diff_main(self.prototype.body, self.body) return diff @property def diff_prototype_prettyHtml(self): """Generate a diff of statement of type `control_implementation` and its prototype""" if self.statement_type != 'control_implementation': # TODO: Should we return None or raise error because statement is not of type control_implementation? return None if self.prototype is None: # TODO: Should we return None or raise error because statement does not have a prototype? return None dmp = dmp_module.diff_match_patch() diff = dmp.diff_main(self.prototype.body, self.body) return dmp.diff_prettyHtml(diff) # TODO:c # - On Save be sure to replace any '\r\n' with '\n' added by round-tripping with excel @staticmethod def _statement_id_from_control(control_id, part_id): if part_id: return f"{control_id}_smt.{part_id}" else: return f"{control_id}_smt" @property def oscal_statement_id(self): return Statement._statement_id_from_control(self.sid, self.pid) @staticmethod def _statement_id_from_control(control_id, part_id): if part_id: return f"{control_id}_smt.{part_id}" else: return f"{control_id}_smt" @property def oscal_statement_id(self): return Statement._statement_id_from_control(self.sid, self.pid)
class System(auto_prefetch.Model): root_element = auto_prefetch.ForeignKey( Element, related_name="system", on_delete=models.CASCADE, help_text= "The Element that is this System. Element must be type [Application, General Support System]" ) fisma_id = models.CharField(max_length=40, help_text="The FISMA Id of the system", unique=False, blank=True, null=True) # Notes # Retrieve system implementation statements # system = System.objects.get(pk=2) # system.root_element.statements_consumed.filter(statement_type="control_implementation") # # Retrieve system common controls statements # system = System.objects.get(pk=2) # system.root_element.common_controls.all()[0].common_control.legacy_imp_smt # system.root_element.common_controls.all()[0].common_control.body # def __str__(self): return "'System %s id=%d'" % (self.root_element.name, self.id) def __repr__(self): # For debugging. return "'System %s id=%d'" % (self.root_element.name, self.id) # @property # def statements_consumed(self): # smts = self.root_element.statements_consumed.all() # return smts def assign_owner_permissions(self, user): try: permissions = get_perms_for_model(System) for perm in permissions: assign_perm(perm.codename, user, self) return True except: return False def assign_edit_permissions(self, user): try: permissions = ['view_system', 'change_system', 'add_system'] for perm in permissions: assign_perm(perm, user, self) return True except: return False @property def smts_common_controls_as_dict(self): common_controls = self.root_element.common_controls.all() smts_as_dict = {} for cc in common_controls: if cc.common_control.oscal_ctl_id in smts_as_dict: smts_as_dict[cc.common_control.oscal_ctl_id].append(cc) else: smts_as_dict[cc.common_control.oscal_ctl_id] = [cc] return smts_as_dict @property def smts_control_implementation_as_dict(self): smts = self.root_element.statements_consumed.filter( statement_type="control_implementation").order_by('pid') smts_as_dict = {} for smt in smts: if smt.sid in smts_as_dict: smts_as_dict[smt.sid]['control_impl_smts'].append(smt) else: smts_as_dict[smt.sid] = { "control_impl_smts": [smt], "common_controls": [], "combined_smt": "" } return smts_as_dict @cached_property def control_implementation_as_dict(self): pid_current = None # Fetch all selected controls elm = self.root_element selected_controls = elm.controls.all().values("oscal_ctl_id", "uuid") # Get the smts_control_implementations ordered by part, e.g. pid smts = elm.statements_consumed.filter( statement_type="control_implementation").order_by('pid') smts_as_dict = {} # Retrieve all of the existing statements for smt in smts: if smt.sid in smts_as_dict: smts_as_dict[smt.sid]['control_impl_smts'].append(smt) else: try: elementcontrol = self.root_element.controls.get( oscal_ctl_id=smt.sid, oscal_catalog_key=smt.sid_class) smts_as_dict[smt.sid] = { "control_impl_smts": [smt], "common_controls": [], "combined_smt": "", "elementcontrol_uuid": elementcontrol.uuid, "combined_smt_uuid": uuid.uuid4() } except ElementControl.DoesNotExist: # Handle case where Element control does not exist elementcontrol = None smts_as_dict[smt.sid] = { "control_impl_smts": [smt], "common_controls": [], "combined_smt": "", "elementcontrol_uuid": None, "combined_smt_uuid": uuid.uuid4() } # Build combined statement # Define status options impl_statuses = [ "Not implemented", "Planned", "Partially implemented", "Implemented", "Unknown" ] status_str = "" for status in impl_statuses: if (smt.status is not None) and (smt.status.lower() == status.lower()): status_str += f'[x] {status} ' else: status_str += f'<span style="color: #888;">[ ] {status}</span> ' # Conditionally add statement part in the beginning of a block of statements related to a part if smt.pid != "" and smt.pid != pid_current: smts_as_dict[smt.sid]['combined_smt'] += f"{smt.pid}.\n" pid_current = smt.pid # DEBUG # TODO # Poor performance, at least in some instances, appears to being caused by `smt.producer_element.name` # parameter in the below statement. if smt.producer_element: smts_as_dict[smt.sid][ 'combined_smt'] += f"<i>{smt.producer_element.name}</i>\n{status_str}\n\n{smt.body}\n\n" # When "smt.producer_element.name" the provided as a fixed string (e.g, "smt.producer_element.name") # for testing purposes, the loop runs 3x faster # The reference `smt.producer_element.name` appears to be calling the database and creating poor performance # even where there are no statements. # Deprecated implementation of inherited/common controls # Leave commented out until we can fully delete...Greg - 2020-10-12 # # Add in the common controls # for cc in self.root_element.common_controls.all(): # if cc.common_control.oscal_ctl_id in smts_as_dict: # smts_as_dict[smt.sid]['common_controls'].append(cc) # else: # smts_as_dict[cc.common_control.oscal_ctl_id] = {"control_impl_smts": [], "common_controls": [cc], "combined_smt": ""} # # Build combined statement # smts_as_dict[cc.common_control.oscal_ctl_id]['combined_smt'] += "{}\n{}\n\n".format(cc.common_control.name, cc.common_control.body) # Populate any controls from assigned baseline that do not have statements for ec in selected_controls: if ec.get('oscal_ctl_id') not in smts_as_dict: smts_as_dict[ec.get('oscal_ctl_id')] = { "control_impl_smts": [], "common_controls": [], "combined_smt": "", "elementcontrol_uuid": ec.get('ec.uuid'), "combined_smt_uuid": uuid.uuid4() } # Return the dictionary return smts_as_dict @cached_property def controls_status_count(self): """Retrieve counts of control status""" status_list = [ 'Not Implemented', 'Planned', 'Partially Implemented', 'Implemented', 'Unknown' ] status_stats = {} # Fetch all selected controls elm = self.root_element for status in status_list: # Get the smts_control_implementations ordered by part, e.g. pid status_stats[status] = elm.statements_consumed.filter( statement_type="control_implementation", status=status).count() # TODO add index on statement status # Get overall controls addressed (e.g., covered) status_stats['Addressed'] = elm.statements_consumed.filter( statement_type="control_implementation").values('sid').count() return status_stats @cached_property def poam_status_count(self): """Retrieve counts of poam status""" # Temporarily hard code status list status_list = ['Open', 'Closed', "In Progress"] # TODO # Get a unique filter of status list and gather on that... status_stats = {} # Fetch all selected controls elm = self.root_element for status in status_list: # Get the smts_control_implementations ordered by part, e.g. pid status_stats[status] = elm.statements_consumed.filter( statement_type="POAM", status__iexact=status).count() # TODO add index on statement status return status_stats # @property (See below for creation of property from method) def get_producer_elements(self): smts = self.root_element.statements_consumed.all() components = set() for smt in smts: if smt.producer_element: components.add(smt.producer_element) components = list(components) components.sort(key=lambda component: component.name) return components producer_elements = cached_property(get_producer_elements)
class ElementControl(auto_prefetch.Model): element = auto_prefetch.ForeignKey( Element, related_name="controls", on_delete=models.CASCADE, help_text= "The Element (e.g., System, Component, Host) to which controls are associated." ) oscal_ctl_id = models.CharField( max_length=20, help_text="OSCAL formatted Control ID (e.g., au-2.3)", blank=True, null=True) oscal_catalog_key = models.CharField( max_length=100, help_text= "Catalog key from which catalog file can be derived (e.g., 'NIST_SP-800-53_rev4')", blank=True, null=True) created = models.DateTimeField(auto_now_add=True, db_index=True) updated = models.DateTimeField(auto_now=True, db_index=True) smts_updated = models.DateTimeField( auto_now=False, db_index=True, help_text="Store date of most recent statement update", blank=True, null=True) uuid = models.UUIDField( default=uuid.uuid4, editable=True, help_text="A UUID (a unique identifier) for this ElementControl.") # Notes # from controls.oscal import *;from controls.models import *; # e = Element.objects.get(id=8); # e.name; # ecq = ElementControl.objects.filter(element=e); # ec = ecq[0] # ec.oscal_catalog_key # cg = Catalog(ec.oscal_catalog_key) # print(cg.get_flattened_control_as_dict(cg.get_control_by_id(ec.oscal_ctl_id))) # # # Get the flattened oscal control information # ec.get_flattened_oscal_control_as_dict() # # Get Implementation statement if it exists # ec.get_flattened_impl_smt_as_dict() # # # Get an element/system by it's element id # e = Element.objects.get(id=8); # e.name; # # Get all ElementControls for the Element # ec_list = ElementControl.objects.filter(element=e); # for ec in ec_list: # print("OSCAL CONTROL") # print(ec.get_flattened_oscal_control_as_dict()) # print("Implementation Statement") # print(ec.get_flattened_impl_smt_as_dict()) class Meta: unique_together = [('element', 'oscal_ctl_id', 'oscal_catalog_key')] def __str__(self): return "'%s id=%d'" % (self.oscal_ctl_id, self.id) def __repr__(self): # For debugging. return "'%s id=%d'" % (self.oscal_ctl_id, self.id) # Commenting out get_controls_by_element in 0.9.1.53+ because it does # not appear to be used in the code base. # def get_controls_by_element(self, element): # # TODO: Is this method being used? Can it be deleted? # query_set = self.objects.filter(element=element) # selected_controls = {} # for cl in query_set: # selected_controls[cl['oscal_ctl_id']] = {'oscal_ctl_id': cl['oscal_ctl_id'], # 'oscal_catalog_key': cl['oscal_catalog_key'], # 'uuid': cl['uuid'] # } # # Sort # selected_controls = natsorted(selected_controls, key=lambda x: x.oscal_ctl_id.casefold) # return selected_controls def get_flattened_oscal_control_as_dict(self): cg = Catalog.GetInstance(catalog_key=self.oscal_catalog_key) return cg.get_flattened_control_as_dict( cg.get_control_by_id(self.oscal_ctl_id))
class Element(auto_prefetch.Model): name = models.CharField(max_length=250, help_text="Common name or acronym of the element", unique=True, blank=False, null=False) full_name = models.CharField(max_length=250, help_text="Full name of the element", unique=False, blank=True, null=True) description = models.CharField( max_length=255, help_text="Brief description of the Element", unique=False, blank=True, null=True) element_type = models.CharField(max_length=150, help_text="Component type", unique=False, blank=True, null=True) created = models.DateTimeField(auto_now_add=True, db_index=True) updated = models.DateTimeField(auto_now=True, db_index=True) uuid = models.UUIDField( default=uuid.uuid4, editable=True, help_text="A UUID (a unique identifier) for this Element.") import_record = auto_prefetch.ForeignKey( ImportRecord, related_name="import_record_elements", on_delete=models.CASCADE, unique=False, blank=True, null=True, help_text="The Import Record which created this Element.") # Notes # Retrieve Element controls where element is e to answer "What controls selected for a system?" (System is an element.) # element_id = 8 # e = Element.objects.get(id=element_id); # e.controls.all() # # returns <QuerySet ['ac-2 id=1', 'ac-3 id=2', 'au-2 id=3']> # # Retrieve statements # e.statements_consumed.all() # # Retrieve statements that are control implementations # e.statements_consumed.filter(statement_type="control_implementation") def __str__(self): return "'%s id=%d'" % (self.name, self.id) def __repr__(self): # For debugging. return "'%s id=%d'" % (self.name, self.id) def assign_owner_permissions(self, user): try: permissions = get_perms_for_model(Element) for perm in permissions: assign_perm(perm.codename, user, self) return True except: return False def assign_edit_permissions(self, user): try: permissions = ['view_element', 'change_element', 'add_element'] for perm in permissions: assign_perm(perm, user, self) return True except: return False def assign_baseline_controls(self, user, baselines_key, baseline_name): """Assign set of controls from baseline to an element""" # Usage # s = System.objects.get(pk=20) # s.root_element.assign_baseline_controls('NIST_SP-800-53_rev4', 'low') can_assign_controls = user.has_perm('change_element', self) # Does user have edit permissions on system? if can_assign_controls: from controls.models import Baselines bs = Baselines() controls = bs.get_baseline_controls(baselines_key, baseline_name) for oscal_ctl_id in controls: ec = ElementControl(element=self, oscal_ctl_id=oscal_ctl_id, oscal_catalog_key=baselines_key) ec.save() return True else: # print("User does not have permission to assign selected controls to element's system.") return False def statements(self, statement_type): """Return on the statements of statement_type produced by this element""" smts = Statement.objects.filter(producer_element=self, statement_type=statement_type) return smts @property def get_control_impl_smts_prototype_count(self): """Return count of statements with this element as producer_element""" smt_count = Statement.objects.filter( producer_element=self, statement_type="control_implementation_prototype").count() return smt_count @transaction.atomic def copy(self, name=None): """Return a copy of an existing system element as a new element with duplicate control_implementation_prototype statements""" # Copy only elements that are components. Do not copy an element of type "system" # Components that are systems should always be associated with a project (at least currently). # Also, statement structure for a system would be very different. if self.element_type == "system": raise SystemException("Copying an entire system is not permitted.") e_copy = deepcopy(self) e_copy.id = None if name is not None: e_copy.name = name else: e_copy.name = self.name + " copy" e_copy.save() # Copy prototype statements from existing element for smt in self.statements("control_implementation_prototype"): smt_copy = deepcopy(smt) smt_copy.producer_element = e_copy smt_copy.consumer_element_id = None smt_copy.id = None smt_copy.save() return e_copy @property def selected_controls_oscal_ctl_ids(self): """Return array of selectecd controls oscal ids""" # oscal_ids = self.controls.all() oscal_ctl_ids = [ control.oscal_ctl_id for control in self.controls.all() ] # Sort oscal_ctl_ids = natsorted(oscal_ctl_ids, key=str.casefold) return oscal_ctl_ids
class Post(RulesModelMixin, auto_prefetch.Model, metaclass=RulesModelBase): """Post Model A model for Blog Posts Args: RulesModelMixin ([type]): [description] auto_prefetch ([type]): [description] metaclass ([type], optional): [description]. Defaults to RulesModelBase. Returns: Post: A model for Post """ PUBLICATION_CHOICES = [ ("P", "Published"), ("W", "Withdrawn"), ("D", "Draft"), ] FEATURING_CHOICES = [ ("F", "Featured"), ("FB", "Featured Big"), ("N", "Not Featured"), ] LANGUAGE_CHOICES = [ ("EN", "English"), ("FR", "French"), ("ML", "Multi Linguistic"), ("OL", "Other Language"), ("NS", "Not Specified"), ] author = auto_prefetch.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="post_author", help_text="Post author", ) title = models.CharField(max_length=200, help_text="Post title") featured_title = models.CharField(max_length=27, default="", blank=True, help_text="Featured post title") body = MarkdownxField(help_text="Post main content", blank=True) image = models.ImageField(null=True, blank=True, upload_to="images/post/", help_text="Post image") description = models.TextField(help_text="Post description") slug = models.SlugField(unique=True, max_length=200, help_text="Post slug") categories = models.ManyToManyField("blog.Category", through="PostCatsLink", help_text="Post categories") tags = TaggableManager(blank=True, through=CustomTaggedItem) series = auto_prefetch.ForeignKey( "blog.Series", on_delete=models.CASCADE, related_name="post_series", help_text="Post series", blank=True, null=True, ) order_in_series = models.PositiveIntegerField( default=0, help_text="Post order in its series") created_date = models.DateTimeField(default=timezone.now, help_text="Creation date") mod_date = models.DateTimeField(auto_now=True, help_text="Last modification") pub_date = models.DateTimeField(blank=True, null=True, help_text="Publication date") publication_state = models.CharField( max_length=25, verbose_name="Publication", choices=PUBLICATION_CHOICES, default="D", help_text="Post publication state", ) withdrawn = models.BooleanField(default=False, help_text="Is Post withdrawn") featuring_state = models.CharField( max_length=25, verbose_name="Featuring", choices=FEATURING_CHOICES, default="N", help_text="Featuring state", ) language = models.CharField( max_length=25, verbose_name="Language", choices=LANGUAGE_CHOICES, default="EN", help_text="What's the main language", ) is_outdated = models.BooleanField(default=False, help_text="Is Post content's outdated") url_to_article = models.URLField( default="", blank=True, help_text="Url to page that inspired the Post") url_to_article_title = models.CharField( max_length=200, default="", blank=True, help_text="What will be shown as url name", ) clicks = models.IntegerField( default=0, help_text="How many times the Post has been seen") rnd_choice = models.IntegerField( default=0, help_text="How many times the Post has been randomly chosen") history = HistoricalRecords() is_removed = models.BooleanField("is removed", default=False, db_index=True, help_text=("Soft delete")) needs_reviewing = models.BooleanField(default=False, help_text=("Needs reviewing")) enable_comments = models.BooleanField(default=True) objects: PostManager = PostManager() class Meta: """Meta class for Post Model""" ordering = ["-pub_date"] get_latest_by = ["id"] rules_permissions = { "add": rules.is_superuser, "update": rules.is_superuser, } def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: max_length = Post._meta.get_field("slug").max_length self.slug = orig = slugify(self.title)[:max_length] for x in itertools.count(2): if (self.pk and Post.objects.filter( Q(slug=self.slug), Q(author=self.author), Q(id=self.pk), ).exists()): break if not Post.objects.filter(slug=self.slug).exists(): break # Truncate & Minus 1 for the hyphen. self.slug = "%s-%d" % (orig[:max_length - len(str(x)) - 1], x) return super().save(*args, **kwargs) def save_without_historical_record(self, *args, **kwargs): self.skip_history_when_saving = True try: ret = self.save(*args, **kwargs) finally: del self.skip_history_when_saving return ret def get_absolute_url(self): return reverse("blog:post_detail", kwargs={"slug": self.slug}) def get_absolute_update_url(self): return reverse("blog:post_edit", kwargs={"slug": self.slug}) def get_absolute_needs_review_url(self): return reverse("blog:post_needs_review", kwargs={"slug": self.slug}) def get_absolute_delete_url(self): return reverse("blog:post_remove", kwargs={"slug": self.slug}) def get_absolute_publish_url(self): return reverse("blog:post_publish", kwargs={"slug": self.slug}) def get_absolute_publish_withdrawn_url(self): return reverse("blog:post_publish_withdrawn", kwargs={"slug": self.slug}) def get_absolute_clone_url(self): return reverse("blog:clone_post", kwargs={"slug": self.slug}) def get_absolute_admin_update_url(self): return reverse("admin:blog_post_change", kwargs={"object_id": self.pk}) def publish(self): self.pub_date = timezone.now() self.publication_state = "P" self.withdrawn = False self.save() def publish_withdrawn(self): self.pub_date = timezone.now() self.publication_state = "W" self.withdrawn = True self.save() def needs_review(self): self.needs_reviewing = True self.save() def clicked(self): self.clicks += 1 self.save_without_historical_record(update_fields=["clicks"]) def rnd_chosen(self): self.rnd_choice += 1 self.save_without_historical_record(update_fields=["rnd_choice"]) def was_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date <= now def remove(self): self.is_removed = True self.save() # Create a property that returns the markdown instead @property def formatted_markdown(self): return markdownify(self.body) @property def is_scheduled(self) -> bool: now = timezone.now() if not self.pub_date: return False return self.pub_date >= now @property def author_name(self): return self.author.username @property def get_tags(self): return self.tags.filter(withdrawn=False) @property def get_admin_tags(self): return self.tags.all() @property def get_featured_cat(self): for post_cat in PostCatsLink.objects.filter( post_id=self.pk, category__is_removed=False, featured_cat=True).select_related("post", "category"): return post_cat @property def featured_cat_title(self): for post_cat in PostCatsLink.objects.filter( post_id=self.pk, category__is_removed=False, featured_cat=True).select_related("post", "category"): return post_cat.category.full_title def get_index_view_url(self): content_type = ContentType.objects.get_for_model(self.__class__) return reverse("%s:%s_list" % (content_type.app_label, content_type.model))
class Migration(migrations.Migration): initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='Integration', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateTimeField(auto_now_add=True, db_index=True)), ('updated', models.DateTimeField(auto_now=True, db_index=True, null=True)), ('name', models.CharField(help_text='Endpoint name in lowercase', max_length=250)), ('description', models.TextField( blank=True, default='', help_text='Brief description of the Integration', null=True)), ('config', jsonfield.fields.JSONField( blank=True, default=dict, help_text='Integration configuration', null=True)), ('config_schema', jsonfield.fields.JSONField(blank=True, default=dict, help_text='Integration schema', null=True)), ], options={ 'abstract': False, }, ), migrations.CreateModel( name='HistoricalEndpoint', fields=[ ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), ('created', models.DateTimeField(blank=True, db_index=True, editable=False)), ('updated', models.DateTimeField(blank=True, db_index=True, editable=False, null=True)), ('endpoint_path', models.CharField(blank=True, help_text='Path to the Endpoint', max_length=250, null=True)), ('description', models.TextField( blank=True, default='', help_text='Brief description of the endpoint', null=True)), ('element_type', models.CharField(blank=True, help_text='Component type', max_length=150, null=True)), ('data', jsonfield.fields.JSONField( blank=True, default=dict, help_text='JSON object representing the API results.', null=True)), ('history_id', models.AutoField(primary_key=True, serialize=False)), ('history_date', models.DateTimeField()), ('history_change_reason', models.CharField(max_length=100, null=True)), ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), ('history_user', models.ForeignKey( null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), ('integration', auto_prefetch.ForeignKey( blank=True, db_constraint=False, help_text="Endpoint's Integration", null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='integrations.integration')), ], options={ 'verbose_name': 'historical endpoint', 'ordering': ('-history_date', '-history_id'), 'get_latest_by': 'history_date', }, bases=(simple_history.models.HistoricalChanges, models.Model), ), migrations.CreateModel( name='Endpoint', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateTimeField(auto_now_add=True, db_index=True)), ('updated', models.DateTimeField(auto_now=True, db_index=True, null=True)), ('endpoint_path', models.CharField(blank=True, help_text='Path to the Endpoint', max_length=250, null=True)), ('description', models.TextField( blank=True, default='', help_text='Brief description of the endpoint', null=True)), ('element_type', models.CharField(blank=True, help_text='Component type', max_length=150, null=True)), ('data', jsonfield.fields.JSONField( blank=True, default=dict, help_text='JSON object representing the API results.', null=True)), ('integration', auto_prefetch.ForeignKey( help_text="Endpoint's Integration", on_delete=django.db.models.deletion.CASCADE, related_name='endpoints', to='integrations.integration')), ], options={ 'abstract': False, 'base_manager_name': 'prefetch_manager', }, managers=[ ('objects', django.db.models.manager.Manager()), ('prefetch_manager', django.db.models.manager.Manager()), ], ), ]
class SubProject(BasePortfolioAbstractModel): """Model for SubProject""" parent_project = auto_prefetch.ForeignKey( "portfolio.Project", on_delete=models.CASCADE, related_name="sub_project", blank=True, null=True, ) link_in_repo = models.CharField(max_length=255, default="", blank=True) featured = models.BooleanField(default=False) class Meta(BasePortfolioAbstractModel.Meta): """Meta class for SubProject Model Class""" ordering = ["pk"] def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.full_title) return super().save(*args, **kwargs) def get_absolute_url(self): return reverse("portfolio:sub_project_detail", kwargs={ "slug": self.parent_project.slug, "subproject_slug": self.slug }) def get_absolute_update_url(self): return reverse("portfolio:sub_project_edit", kwargs={ "slug": self.parent_project.slug, "subproject_slug": self.slug }) def get_absolute_delete_url(self): return reverse("portfolio:sub_project_delete", kwargs={ "slug": self.parent_project.slug, "subproject_slug": self.slug }) def get_absolute_admin_update_url(self): return reverse("admin:portfolio_subproject_change", kwargs={"object_id": self.pk}) @property def full_title(self) -> str: fulltitle = "" fulltitle = self.parent_project.title + " " + self.title return fulltitle def remove(self): self.is_removed = True self.save() def get_index_view_url(self): content_type = ContentType.objects.get_for_model(self.__class__) return reverse("%s:%s_list" % (content_type.app_label, content_type.model))