datatracker/ietf/ipr/models.py
Henrik Levkowetz aa5e61d958 Updated all urlpatterns to use ietf.utils.urls.url() instead of django's,
in order to autogenerate dotted path url pattern names.  Updated a number
of url reverses to use dotted path, and removed explicit url pattern names
as needed.

Changed some imports to prevent import of ietf.urls before django
initialization was complete.


Changed 3 cases of form classes being curried to functions; django 1.10
didn't accept that.

Started converting old-style middleware classes to new-style middleware
functions (incomplete).

Tweaked a nomcom decorator to preserve function names and attributes, like
a good decorator should.

Replaced the removed django templatetag 'removetags' with our own version
which uses bleach, and does sanitizing in addition to removing explicitly
mentionied html tags.

Rewrote the filename argument handling in a management command which had
broken with the upgrade.
 - Legacy-Id: 12818
2017-02-11 14:43:01 +00:00

209 lines
9 KiB
Python

# Copyright The IETF Trust 2007, All Rights Reserved
import datetime
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from ietf.doc.models import DocAlias
from ietf.name.models import DocRelationshipName,IprDisclosureStateName,IprLicenseTypeName,IprEventTypeName
from ietf.person.models import Person
from ietf.message.models import Message
class IprDisclosureBase(models.Model):
by = models.ForeignKey(Person) # who was logged in, or System if nobody was logged in
compliant = models.BooleanField("Complies to RFC3979", default=True)
docs = models.ManyToManyField(DocAlias, through='IprDocRel')
holder_legal_name = models.CharField(max_length=255)
notes = models.TextField("Additional notes", blank=True)
other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255)
rel = models.ManyToManyField('self', through='RelatedIpr', symmetrical=False)
state = models.ForeignKey(IprDisclosureStateName)
submitter_name = models.CharField(max_length=255,blank=True)
submitter_email = models.EmailField(blank=True)
time = models.DateTimeField(auto_now_add=True)
title = models.CharField(blank=True, max_length=255)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return settings.IDTRACKER_BASE_URL + reverse('ietf.ipr.views.show',kwargs={'id':self.id})
def get_child(self):
"""Returns the child instance"""
for child_class in ('genericiprdisclosure',
'holderiprdisclosure',
'nondocspecificiprdisclosure',
'thirdpartyiprdisclosure'):
try:
return getattr(self,child_class)
except IprDisclosureBase.DoesNotExist:
pass
def get_latest_event_msgout(self):
"""Returns the latest IprEvent of type msgout. For use in templates."""
return self.latest_event(type='msgout')
def has_legacy_event(self):
"""Returns True if there is one or more LegacyMigrationIprEvents
for this disclosure"""
if LegacyMigrationIprEvent.objects.filter(disclosure=self):
return True
else:
return False
def latest_event(self, *args, **filter_args):
"""Get latest event of optional Python type and with filter
arguments, e.g. d.latest_event(type="xyz") returns an IprEvent
while d.latest_event(WriteupDocEvent, type="xyz") returns a
WriteupDocEvent event."""
model = args[0] if args else IprEvent
e = model.objects.filter(disclosure=self).filter(**filter_args).order_by('-time', '-id')[:1]
return e[0] if e else None
def set_state(self, state):
"""This just sets the state, doesn't log the change. Takes a string"""
try:
statename = IprDisclosureStateName.objects.get(slug=state)
except IprDisclosureStateName.DoesNotExist:
return
self.state = statename
self.save()
@property
def updates(self):
"""Shortcut for disclosures this disclosure updates"""
return self.relatedipr_source_set.filter(relationship__slug='updates')
@property
def updated_by(self):
"""Shortcut for disclosures this disclosure is updated by"""
return self.relatedipr_target_set.filter(relationship__slug='updates')
@property
def update_notified_date(self):
"""Returns the date when the submitters of the IPR that this IPR updates
were notified"""
e = self.latest_event(type='update_notify')
if e:
return e.time
else:
return None
def recursively_updates(self,disc_set=None):
"""Returns the set of disclosures updated directly or transitively by this disclosure"""
if disc_set == None:
disc_set = set()
new_candidates = set([y.target.get_child() for y in self.updates])
unseen = new_candidates - disc_set
disc_set.update(unseen)
for disc in unseen:
disc_set.update(disc.recursively_updates(disc_set))
return disc_set
class HolderIprDisclosure(IprDisclosureBase):
ietfer_name = models.CharField(max_length=255, blank=True) # "Whose Personal Belief Triggered..."
ietfer_contact_email = models.EmailField(blank=True)
ietfer_contact_info = models.TextField(blank=True)
patent_info = models.TextField()
has_patent_pending = models.BooleanField(default=False)
holder_contact_email = models.EmailField()
holder_contact_name = models.CharField(max_length=255)
holder_contact_info = models.TextField(blank=True, help_text="Address, phone, etc.")
licensing = models.ForeignKey(IprLicenseTypeName)
licensing_comments = models.TextField(blank=True)
submitter_claims_all_terms_disclosed = models.BooleanField(default=False)
class ThirdPartyIprDisclosure(IprDisclosureBase):
ietfer_name = models.CharField(max_length=255) # "Whose Personal Belief Triggered..."
ietfer_contact_email = models.EmailField()
ietfer_contact_info = models.TextField(blank=True, help_text="Address, phone, etc.")
patent_info = models.TextField()
has_patent_pending = models.BooleanField(default=False)
class NonDocSpecificIprDisclosure(IprDisclosureBase):
'''A Generic IPR Disclosure w/ patent information'''
holder_contact_name = models.CharField(max_length=255)
holder_contact_email = models.EmailField()
holder_contact_info = models.TextField(blank=True, help_text="Address, phone, etc.")
patent_info = models.TextField()
has_patent_pending = models.BooleanField(default=False)
statement = models.TextField() # includes licensing info
class GenericIprDisclosure(IprDisclosureBase):
holder_contact_name = models.CharField(max_length=255)
holder_contact_email = models.EmailField()
holder_contact_info = models.TextField(blank=True, help_text="Address, phone, etc.")
statement = models.TextField() # includes licensing info
class IprDocRel(models.Model):
disclosure = models.ForeignKey(IprDisclosureBase)
document = models.ForeignKey(DocAlias)
sections = models.TextField(blank=True)
revisions = models.CharField(max_length=16,blank=True) # allows strings like 01-07
def doc_type(self):
name = self.document.name
if name.startswith("rfc"):
return "RFC"
if name.startswith("draft"):
return "Internet-Draft"
if name.startswith("slide"):
return "Meeting Slide"
def formatted_name(self):
name = self.document.name
if name.startswith("rfc"):
return name.upper()
#elif self.revisions:
# return "%s-%s" % (name, self.revisions)
else:
return name
def __unicode__(self):
if self.revisions:
return u"%s which applies to %s-%s" % (self.disclosure, self.document.name, self.revisions)
else:
return u"%s which applies to %s" % (self.disclosure, self.document.name)
class RelatedIpr(models.Model):
source = models.ForeignKey(IprDisclosureBase,related_name='relatedipr_source_set')
target = models.ForeignKey(IprDisclosureBase,related_name='relatedipr_target_set')
relationship = models.ForeignKey(DocRelationshipName) # Re-use; change to a dedicated RelName if needed
def __unicode__(self):
return u"%s %s %s" % (self.source.title, self.relationship.name.lower(), self.target.title)
class IprEvent(models.Model):
time = models.DateTimeField(auto_now_add=True)
type = models.ForeignKey(IprEventTypeName)
by = models.ForeignKey(Person)
disclosure = models.ForeignKey(IprDisclosureBase)
desc = models.TextField()
message = models.ForeignKey(Message, null=True, blank=True,related_name='msgevents')
in_reply_to = models.ForeignKey(Message, null=True, blank=True,related_name='irtoevents')
response_due= models.DateTimeField(blank=True,null=True)
def __unicode__(self):
return u"%s %s by %s at %s" % (self.disclosure.title, self.type.name.lower(), self.by.plain_name(), self.time)
def response_past_due(self):
"""Returns true if it's beyond the response_due date and no response has been
received"""
qs = IprEvent.objects.filter(disclosure=self.disclosure,in_reply_to=self.message)
if not qs and datetime.datetime.now().date() > self.response_due.date():
return True
else:
return False
class Meta:
ordering = ['-time', '-id']
class LegacyMigrationIprEvent(IprEvent):
"""A subclass of IprEvent specifically for capturing contents of legacy_url_0,
the text of a disclosure submitted by email"""
pass