class Person(ShareObject): family_name = models.TextField(blank=True, db_index=True) # last given_name = models.TextField(blank=True, db_index=True) # first additional_name = models.TextField(blank=True, db_index=True) # can be used for middle suffix = models.TextField(blank=True, db_index=True) emails = ShareManyToManyField(Email, through='PersonEmail') affiliations = ShareManyToManyField('Entity', through='Affiliation') # this replaces "authority_id" and "other_identifiers" in the diagram identifiers = ShareManyToManyField(Identifier, through='ThroughIdentifiers') location = models.TextField(blank=True) url = ShareURLField(blank=True) def __str__(self): return self.get_full_name() def get_full_name(self): return ' '.join(x for x in [ self.given_name, self.family_name, self.additional_name, self.suffix ] if x) class Meta: verbose_name_plural = 'People' index_together = (('family_name', 'given_name', 'additional_name', 'suffix'))
class AbstractAgent(ShareObject, metaclass=TypedShareObjectMeta): """ An Agent is an entity that has the power to act, e.g. an individual person or a group of people. Agents make decisions and produce or contribute to the production of creative works. """ name = models.TextField(blank=True, db_index=True) location = models.TextField(blank=True) related_agents = ShareManyToManyField('AbstractAgent', through='AbstractAgentRelation', through_fields=('subject', 'related'), symmetrical=False) related_works = ShareManyToManyField('AbstractCreativeWork', through='AbstractAgentWorkRelation') matching_criteria = MatchByOneToMany('identifiers') class Meta(ShareObject.Meta): db_table = 'share_agent' index_together = (( 'type', 'name', )) def __str__(self): return self.name
class AbstractCreativeWork(ShareObject, metaclass=TypedShareObjectMeta): title = models.TextField(blank=True) description = models.TextField(blank=True) contributors = ShareManyToManyField(Person, through='Contributor') awards = ShareManyToManyField(Award, through='ThroughAwards') venues = ShareManyToManyField(Venue, through='ThroughVenues') links = ShareManyToManyField('Link', through='ThroughLinks') funders = ShareManyToManyField('Funder', through='Association') publishers = ShareManyToManyField('Publisher', through='Association') institutions = ShareManyToManyField('Institution', through='Association') organizations = ShareManyToManyField('Organization', through='Association') subject = ShareForeignKey(Tag, related_name='subjected_%(class)s', null=True) # Note: Null allows inserting of None but returns it as an empty string tags = ShareManyToManyField(Tag, related_name='tagged_%(class)s', through='ThroughTags') date_created = models.DateTimeField(null=True, db_index=True) date_published = models.DateTimeField(null=True, db_index=True) date_updated = models.DateTimeField(null=True, db_index=True) free_to_read_type = ShareURLField(blank=True, db_index=True) free_to_read_date = models.DateTimeField(null=True, db_index=True) rights = models.TextField(blank=True, null=True, db_index=True) language = models.TextField(blank=True, null=True, db_index=True) def __str__(self): return self.title
class AbstractCreativeWork(ShareObject, metaclass=TypedShareObjectMeta): title = models.TextField(blank=True, help_text='') description = models.TextField(blank=True, help_text='') is_deleted = models.BooleanField( default=False, help_text= _('Determines whether or not this record will be discoverable via search.' )) date_published = models.DateTimeField(null=True) date_updated = models.DateTimeField(null=True) free_to_read_type = ShareURLField(blank=True) free_to_read_date = models.DateTimeField(null=True) rights = models.TextField(blank=True, null=True) language = models.TextField( blank=True, null=True, help_text= _('The ISO 3166-1 alpha-2 country code indicating the language of this record.' )) subjects = ShareManyToManyField(Subject, related_name='subjected_works', through='ThroughSubjects') tags = ShareManyToManyField(Tag, related_name='tagged_works', through='ThroughTags') related_agents = ShareManyToManyField('AbstractAgent', through='AbstractAgentWorkRelation') related_works = ShareManyToManyField('AbstractCreativeWork', through='AbstractWorkRelation', through_fields=('subject', 'related'), symmetrical=False) @classmethod def normalize(self, node, graph): for k, v in tuple(node.attrs.items()): if isinstance(v, str): node.attrs[k] = strip_whitespace(v) if node.attrs[k] == 'null': node.attrs[k] = '' class Disambiguation: any = ('identifiers', ) class Meta: db_table = 'share_creativework' def __str__(self): return self.title
class Award(ShareObject): # ScholarlyArticle has an award object # it's just a text field, I assume our 'description' covers it. award = ShareURLField(blank=True) description = models.TextField(blank=True) url = ShareURLField(blank=True) entities = ShareManyToManyField('Entity', through='ThroughAwardEntities') def __str__(self): return self.description
class AbstractCreativeWork(ShareObject, metaclass=TypedShareObjectMeta): title = models.TextField(blank=True) description = models.TextField(blank=True) # Used to determine if something should be surfaced in ES or not # this may need to be renamed later is_deleted = models.BooleanField(default=False) contributors = ShareManyToManyField(Person, through='Contributor') awards = ShareManyToManyField(Award, through='ThroughAwards') venues = ShareManyToManyField(Venue, through='ThroughVenues') links = ShareManyToManyField('Link', through='ThroughLinks') funders = ShareManyToManyField('Funder', through='Association') publishers = ShareManyToManyField('Publisher', through='Association') institutions = ShareManyToManyField('Institution', through='Association') organizations = ShareManyToManyField('Organization', through='Association') subjects = ShareManyToManyField(Subject, related_name='subjected_%(class)s', through='ThroughSubjects') # Note: Null allows inserting of None but returns it as an empty string tags = ShareManyToManyField(Tag, related_name='tagged_%(class)s', through='ThroughTags') date_published = models.DateTimeField(null=True, db_index=True) date_updated = models.DateTimeField(null=True, db_index=True) free_to_read_type = ShareURLField(blank=True, db_index=True) free_to_read_date = models.DateTimeField(null=True, db_index=True) rights = models.TextField(blank=True, null=True, db_index=True) language = models.TextField(blank=True, null=True, db_index=True) def __str__(self): return self.title
class Entity(ShareObject, metaclass=TypedShareObjectMeta): url = ShareURLField(blank=True) name = models.TextField() location = models.TextField(blank=True) affiliations = ShareManyToManyField('Person', through='Affiliation') class Meta: verbose_name_plural = 'Entities' index_together = (( 'type', 'name', )) def __str__(self): return self.name
class AbstractAgent(ShareObject, metaclass=TypedShareObjectMeta): """ An Agent is an entity that has the power to act, e.g. an individual person or a group of people. Agents make decisions and produce or contribute to the production of creative works. """ name = models.TextField(blank=True, db_index=True) location = models.TextField(blank=True) related_agents = ShareManyToManyField('AbstractAgent', through='AbstractAgentRelation', through_fields=('subject', 'related'), symmetrical=False) related_works = ShareManyToManyField('AbstractCreativeWork', through='AbstractAgentWorkRelation') @classmethod def normalize(cls, node, graph): if 'name' not in node.attrs and not node.is_blank: return name = strip_whitespace(node.attrs['name']) # Slightly more intellegent title casing name = re.sub(r'(?!for|and|the)\b[a-z]\w{2,}', lambda x: x.group().title(), name) if NULL_RE.match(name): logger.debug('Discarding unnamed agent "%s"', name) return graph.remove(node) maybe_type = GuessAgentTypeLink(default=node.type).execute( node.attrs['name']) # If the new type is MORE specific, IE encompasses FEWER types, upgrade. Otherwise ignore if len(apps.get_model('share', maybe_type).get_types()) < len( node.model.get_types()): node._type = maybe_type match = re.match( r'^(.*(?:Departa?ment|Institute).+?);(?: (.+?); )?([^;]+)$', name, re.I) if match: *parts, location = [ strip_whitespace(x) for x in match.groups() if x and strip_whitespace(x) ] node.attrs['name'] = ' - '.join(reversed(parts)) node.attrs['location'] = location return match = re.match(r'^(.+?), ([^,]+), ([^,]+)$', name, re.I) if match: name, *location = [ strip_whitespace(x) for x in match.groups() if x and strip_whitespace(x) ] node.attrs['name'] = name node.attrs['location'] = ', '.join(location) node.attrs['name'] = name if node.attrs.get('location'): node.attrs['location'] = strip_whitespace(node.attrs['location']) class Disambiguation: any = ('identifiers', 'work_relations') class Meta: db_table = 'share_agent' index_together = (( 'type', 'name', )) def __str__(self): return self.name
class AbstractCreativeWork(ShareObject, metaclass=TypedShareObjectMeta): title = models.TextField(blank=True, help_text='') description = models.TextField(blank=True, help_text='') is_deleted = models.BooleanField( default=False, help_text= _('Determines whether or not this record will be discoverable via search.' )) date_published = models.DateTimeField(blank=True, null=True) date_updated = models.DateTimeField(blank=True, null=True) free_to_read_type = ShareURLField(blank=True) free_to_read_date = models.DateTimeField(blank=True, null=True) rights = models.TextField(blank=True, null=True) language = models.TextField( blank=True, null=True, help_text= _('The ISO 3166-1 alpha-2 country code indicating the language of this record.' )) subjects = ShareManyToManyField(Subject, related_name='subjected_works', through='ThroughSubjects') tags = ShareManyToManyField(Tag, related_name='tagged_works', through='ThroughTags') related_agents = ShareManyToManyField('AbstractAgent', through='AbstractAgentWorkRelation') related_works = ShareManyToManyField('AbstractCreativeWork', through='AbstractWorkRelation', through_fields=('subject', 'related'), symmetrical=False) @classmethod def normalize(self, node, graph): for k, v in tuple(node.attrs.items()): if isinstance(v, str): node.attrs[k] = strip_whitespace(v) if node.attrs[k] == 'null': node.attrs[k] = '' class Disambiguation: any = ('identifiers', ) class Meta(ShareObject.Meta): db_table = 'share_creativework' verbose_name_plural = 'Creative Works' def defrankenize(self, *_, im_really_sure_about_this=False): if not im_really_sure_about_this: raise ValueError('You have to be really sure about this') logger.info('Defrankenizing %r', self) with transaction.atomic(): logger.info('Removing relations') for field in AbstractCreativeWork._meta.get_fields(): if not field.one_to_many or field.name in ('changes', 'versions'): continue logger.warning('Removing all %s', field.related_name) relation = getattr(self, field.get_accessor_name()) num_deleted, stats = Change.objects.filter( id__in=relation.values_list('change_id', flat=True)).delete() logger.warning('Deleted %d changes to remove %s', num_deleted, field.related_name) assert num_deleted == stats.pop('share.Change', 0) if stats: logger.error('Unexpectedly removed other rows, %r', stats) raise ValueError( 'Unexpectedly removed other rows, {!r}'.format(stats)) logger.info('Relations removed') self.administrative_change(is_deleted=True, title='Defrankenized work') def __str__(self): return self.title