示例#1
0
def setup_generic_relations(model_class):
    """
    Set up GenericRelations for actionable models.
    """
    Action = apps.get_model('actstream', 'action')

    if Action is None:
        raise RegistrationError(
            'Unable get actstream.Action. Potential circular imports '
            'in initialisation. Try moving actstream app to come after the '
            'apps which have models to register in the INSTALLED_APPS setting.'
        )

    related_attr_name = 'related_query_name'
    related_attr_value = 'actions_with_%s' % label(model_class)

    relations = {}
    for field in ('actor', 'target', 'action_object'):
        attr = '%s_actions' % field
        attr_value = '%s_as_%s' % (related_attr_value, field)
        kwargs = {
            'content_type_field': '%s_content_type' % field,
            'object_id_field': '%s_object_id' % field,
            related_attr_name: attr_value
        }
        rel = GenericRelation('actstream.Action', **kwargs)
        rel.contribute_to_class(model_class, attr)
        relations[field] = rel

        # @@@ I'm not entirely sure why this works
        setattr(Action, attr_value, None)
    return relations
def genericm2m_inlineformset_factory(source_model, model, form=forms.ModelForm,
                          formset=GenericM2MInlineFormSet, fk_name=None,
                          fields=None, exclude=None, extra=3, can_order=True,
                          can_delete=True, max_num=None,
                          formfield_callback=None):
    """
    Returns an ``InlineFormSet`` for the given kwargs.

    You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
    to ``source_model``.
    """
    fk = GenericRelation(
        source_model,
        verbose_name='source',
        related_query_name=fk_name or 'related')
    fk.name = 'source'
    kwargs = {
        'form': form,
        'formfield_callback': formfield_callback,
        'formset': GenericM2MInlineFormSet,
        'extra': extra,
        'can_delete': can_delete,
        'can_order': can_order,
        'fields': fields,
        'exclude': exclude,
        'max_num': max_num,
    }
    FormSet = forms.models.modelformset_factory(model, **kwargs)  # NOQA
    FormSet.fk = fk
    FormSet.source_type_field = 'source_type'
    return FormSet
示例#3
0
    def post_through_setup(self, cls):
        if RelatedObject is not None:  # Django < 1.8
            self.related = RelatedObject(cls, self.model, self)

        self.use_gfk = (
            self.through is None or issubclass(self.through, CommonGenericTaggedItemBase)
        )

        # rel.to renamed to remote_field.model in Django 1.9
        if VERSION >= (1, 9):
            if not self.remote_field.model:
                self.remote_field.model = self.through._meta.get_field("tag").remote_field.model
        else:
            if not self.rel.to:
                self.rel.to = self.through._meta.get_field("tag").rel.to

        if RelatedObject is not None:  # Django < 1.8
            self.related = RelatedObject(self.through, cls, self)

        if self.use_gfk:
            tagged_items = GenericRelation(self.through)
            tagged_items.contribute_to_class(cls, 'tagged_items')

        for rel in cls._meta.local_many_to_many:
            if rel == self or not isinstance(rel, TaggableManager):
                continue
            if rel.through == self.through:
                raise ValueError('You can\'t have two TaggableManagers with the'
                                 ' same through model.')
 def post_through_setup(self, cls):
   self.use_gfk = (
     self.through is None
   )
   self.rel.to = self.through._meta.get_field("group").rel.to
   if RelatedObject is not None:
     self.related = RelatedObject(self.through, cls, self)
   if self.use_gfk:
     groups = GenericRelation(self.through)
     groups.contribute_to_class(cls, "groups")
示例#5
0
def contribute_to_class(model):
    """
    Adds a 'maat_ranking' attribute to each instance of model.
    The attribute is a generic relation to MaatRanking, used by the
    handler to retrieve the ordered queryset.
    """
    try:
        generic_relation = GenericRelation(MaatRanking)
    except TypeError:
        # Django < 1.7
        generic_relation = GenericRelation(MaatRanking)
    generic_relation.contribute_to_class(model, 'maat_ranking')
示例#6
0
    def _attach_generic_relation(self):
        '''
        Set up the generic relation for the entity
        '''
        rel_name = self.config_cls.generic_relation_related_name or \
                   'entity'

        gr_name = self.config_cls.generic_relation_attr.lower()
        generic_relation = GenericRelation(Value,
                                           object_id_field='entity_id',
                                           content_type_field='entity_ct',
                                           related_query_name=rel_name)
        generic_relation.contribute_to_class(self.model_cls, gr_name)
示例#7
0
def _inject_generic_relation(qs_or_model):
    if isinstance(qs_or_model, models.Model):
        model = qs_or_model
    elif isinstance(qs_or_model, models.QuerySet):
        model = qs_or_model.model
    else:
        raise TypeError('Can`t inject generic relation')

    try:
        model._meta.get_field(MODEL_ATTR_FIELD_NAME)
    except FieldDoesNotExist:
        generic_relation = GenericRelation(
            Attribute, related_query_name=MODEL_ATTR_FIELD_NAME)
        generic_relation.contribute_to_class(model, MODEL_ATTR_FIELD_NAME)
示例#8
0
    def post_through_setup(self, cls):
        self.related = RelatedObject(cls, self.model, self)
        self.use_gfk = (
            self.through is None or issubclass(self.through, GenericTaggedItemBase)
        )
        self.rel.to = self.through._meta.get_field("tag").rel.to
        self.related = RelatedObject(self.through, cls, self)
        if self.use_gfk:
            tagged_items = GenericRelation(self.through)
            tagged_items.contribute_to_class(cls, 'tagged_items')

        for rel in cls._meta.local_many_to_many:
            if rel == self or not isinstance(rel, TaggableManager):
                continue
            if rel.through == self.through:
                raise ValueError('You can\'t have two TaggableManagers with the'
                                 ' same through model.')
示例#9
0
文件: models.py 项目: er587/FIR
def create_link(linkable_model, linked_model, linkable_link_name=None, verbose_name=None, verbose_name_plural=None):

    class LinkedModel(object):
        def __init__(self, model, link_name=None, verbose_name=None, verbose_name_plural=None, reverse_link_name=None):
            self.model = model
            self.link_name = link_name
            self.reverse_link_name = reverse_link_name
            self.verbose_name = verbose_name
            self.verbose_name_plural = verbose_name_plural

    if issubclass(linkable_model, ManyLinkableModel):
        get_link_name = get_plural
    elif issubclass(linkable_model, OneLinkableModel):
        get_link_name = get_singular

    if linkable_link_name is None:
        linkable_link_name = get_link_name(linked_model)
    if verbose_name is None:
        verbose_name = linked_model._meta.verbose_name
    if verbose_name_plural is None:
        verbose_name_plural = linked_model._meta.verbose_name_plural
    linked_link_name = get_plural(linkable_model)

    if issubclass(linkable_model, ManyLinkableModel):
        field = models.ManyToManyField(linkable_model, related_name=linkable_link_name)
        setattr(linked_model, linked_link_name, field)
        field.contribute_to_class(linked_model, linked_link_name)

    elif issubclass(linkable_model, OneLinkableModel):
        linked_link_name = get_singular(linkable_model)+"_set"
        field = GenericRelation(linkable_model, related_query_name=linkable_link_name)
        setattr(linked_model, linked_link_name, field)
        field.contribute_to_class(linked_model, linked_link_name)
        setattr(linkable_model, linkable_link_name, property(
            fget=lambda x: linkable_model.get_related(x),
            fset=lambda x, y: linkable_model.set_related(x, y)))

    if not hasattr(linkable_model, "_LINKS") or linkable_model._LINKS is None:
        setattr(linkable_model, "_LINKS", dict())
    linkable_model._LINKS[linkable_link_name] = LinkedModel(
                                linked_model, link_name=linkable_link_name,
                                verbose_name=verbose_name,
                                verbose_name_plural=verbose_name_plural,
                                reverse_link_name=linked_link_name)
    return linkable_model
示例#10
0
文件: registry.py 项目: gzqichang/wa
def setup_generic_relations(model_class):
    """
    注册过的model_class实例可以如此操作:
        instance.actor_actions.filter(...)
        instance.target_actions.filter(...)
        instance.relative_actions.filter(...)
    """
    from qevent.models import Action
    related_attr_value = 'actions_with_%s' % label(model_class)
    #
    relations = {}
    for field in ('actor', 'target', 'relative'):
        attr_value = '%s_as_%s' % (related_attr_value, field)
        rel = GenericRelation(Action, 
            content_type_field='%s_type' % field,
            object_id_field='%s_object_id' % field,
            related_query_name=attr_value,
        )
        rel.contribute_to_class(model_class, '%s_actions' % field)
        relations[field] = rel
        # setattr(Action, attr_value, None)
    return relations
示例#11
0
文件: models.py 项目: yuta2/netbox
class VLAN(ChangeLoggedModel, CustomFieldModel):
    """
    A VLAN is a distinct layer two forwarding domain identified by a 12-bit integer (1-4094). Each VLAN must be assigned
    to a Site, however VLAN IDs need not be unique within a Site. A VLAN may optionally be assigned to a VLANGroup,
    within which all VLAN IDs and names but be unique.

    Like Prefixes, each VLAN is assigned an operational status and optionally a user-defined Role. A VLAN can have zero
    or more Prefixes assigned to it.
    """
    site = models.ForeignKey(
        to='dcim.Site',
        on_delete=models.PROTECT,
        related_name='vlans',
        blank=True,
        null=True
    )
    group = models.ForeignKey(
        to='ipam.VLANGroup',
        on_delete=models.PROTECT,
        related_name='vlans',
        blank=True,
        null=True
    )
    vid = models.PositiveSmallIntegerField(
        verbose_name='ID',
        validators=[MinValueValidator(1), MaxValueValidator(4094)]
    )
    name = models.CharField(
        max_length=64
    )
    tenant = models.ForeignKey(
        to='tenancy.Tenant',
        on_delete=models.PROTECT,
        related_name='vlans',
        blank=True,
        null=True
    )
    status = models.CharField(
        max_length=50,
        choices=VLANStatusChoices,
        default=VLANStatusChoices.STATUS_ACTIVE
    )
    role = models.ForeignKey(
        to='ipam.Role',
        on_delete=models.SET_NULL,
        related_name='vlans',
        blank=True,
        null=True
    )
    description = models.CharField(
        max_length=100,
        blank=True
    )
    custom_field_values = GenericRelation(
        to='extras.CustomFieldValue',
        content_type_field='obj_type',
        object_id_field='obj_id'
    )

    tags = TaggableManager(through=TaggedItem)

    csv_headers = ['site', 'group_name', 'vid', 'name', 'tenant', 'status', 'role', 'description']
    clone_fields = [
        'site', 'group', 'tenant', 'status', 'role', 'description',
    ]

    STATUS_CLASS_MAP = {
        'active': 'primary',
        'reserved': 'info',
        'deprecated': 'danger',
    }

    class Meta:
        ordering = ('site', 'group', 'vid', 'pk')  # (site, group, vid) may be non-unique
        unique_together = [
            ['group', 'vid'],
            ['group', 'name'],
        ]
        verbose_name = 'VLAN'
        verbose_name_plural = 'VLANs'

    def __str__(self):
        return self.display_name or super().__str__()

    def get_absolute_url(self):
        return reverse('ipam:vlan', args=[self.pk])

    def clean(self):

        # Validate VLAN group
        if self.group and self.group.site != self.site:
            raise ValidationError({
                'group': "VLAN group must belong to the assigned site ({}).".format(self.site)
            })

    def to_csv(self):
        return (
            self.site.name if self.site else None,
            self.group.name if self.group else None,
            self.vid,
            self.name,
            self.tenant.name if self.tenant else None,
            self.get_status_display(),
            self.role.name if self.role else None,
            self.description,
        )

    @property
    def display_name(self):
        if self.vid and self.name:
            return "{} ({})".format(self.vid, self.name)
        return None

    def get_status_class(self):
        return self.STATUS_CLASS_MAP[self.status]

    def get_members(self):
        # Return all interfaces assigned to this VLAN
        return Interface.objects.filter(
            Q(untagged_vlan_id=self.pk) |
            Q(tagged_vlans=self.pk)
        ).distinct()
示例#12
0
文件: models.py 项目: yuta2/netbox
class Service(ChangeLoggedModel, CustomFieldModel):
    """
    A Service represents a layer-four service (e.g. HTTP or SSH) running on a Device or VirtualMachine. A Service may
    optionally be tied to one or more specific IPAddresses belonging to its parent.
    """
    device = models.ForeignKey(
        to='dcim.Device',
        on_delete=models.CASCADE,
        related_name='services',
        verbose_name='device',
        null=True,
        blank=True
    )
    virtual_machine = models.ForeignKey(
        to='virtualization.VirtualMachine',
        on_delete=models.CASCADE,
        related_name='services',
        null=True,
        blank=True
    )
    name = models.CharField(
        max_length=30
    )
    protocol = models.CharField(
        max_length=50,
        choices=ServiceProtocolChoices
    )
    port = models.PositiveIntegerField(
        validators=[MinValueValidator(SERVICE_PORT_MIN), MaxValueValidator(SERVICE_PORT_MAX)],
        verbose_name='Port number'
    )
    ipaddresses = models.ManyToManyField(
        to='ipam.IPAddress',
        related_name='services',
        blank=True,
        verbose_name='IP addresses'
    )
    description = models.CharField(
        max_length=100,
        blank=True
    )
    custom_field_values = GenericRelation(
        to='extras.CustomFieldValue',
        content_type_field='obj_type',
        object_id_field='obj_id'
    )

    tags = TaggableManager(through=TaggedItem)

    csv_headers = ['device', 'virtual_machine', 'name', 'protocol', 'description']

    class Meta:
        ordering = ('protocol', 'port', 'pk')  # (protocol, port) may be non-unique

    def __str__(self):
        return '{} ({}/{})'.format(self.name, self.port, self.get_protocol_display())

    def get_absolute_url(self):
        return reverse('ipam:service', args=[self.pk])

    @property
    def parent(self):
        return self.device or self.virtual_machine

    def clean(self):

        # A Service must belong to a Device *or* to a VirtualMachine
        if self.device and self.virtual_machine:
            raise ValidationError("A service cannot be associated with both a device and a virtual machine.")
        if not self.device and not self.virtual_machine:
            raise ValidationError("A service must be associated with either a device or a virtual machine.")

    def to_csv(self):
        return (
            self.device.name if self.device else None,
            self.virtual_machine.name if self.virtual_machine else None,
            self.name,
            self.get_protocol_display(),
            self.port,
            self.description,
        )
示例#13
0
class AbstractProposal(ConferenceRelated, EventInfo):

    submitter = BigForeignKey(
        to=settings.AUTH_USER_MODEL,
        verbose_name=_('submitter'),
    )

    outline = models.TextField(
        verbose_name=_('outline'),
        blank=True,
    )

    objective = EAWTextField(
        verbose_name=_('objective'),
        max_length=1000,
    )

    supplementary = models.TextField(
        verbose_name=_('supplementary'),
        blank=True,
        default='',
    )

    cancelled = models.BooleanField(
        verbose_name=_('cancelled'),
        default=False,
        db_index=True,
    )

    additionalspeaker_set = GenericRelation(
        to=AdditionalSpeaker,
        content_type_field='proposal_type',
        object_id_field='proposal_id',
    )

    objects = DefaultConferenceManager.from_queryset(ProposalQuerySet)()
    all_objects = models.Manager.from_queryset(ProposalQuerySet)()

    _must_fill_fields = [
        'abstract',
        'objective',
        'supplementary',
        'detailed_description',
        'outline',
    ]

    class Meta:
        abstract = True

    @property
    def speakers(self):
        yield PrimarySpeaker(proposal=self)
        additionals = self.additionalspeaker_set.filter(cancelled=False)
        for speaker in additionals.select_related('user'):
            yield speaker

    @property
    def speaker_count(self):
        return self.additionalspeaker_set.filter(cancelled=False).count() + 1

    @property
    def must_fill_fields_count(self):
        return len(self._must_fill_fields)

    @property
    def finished_fields_count(self):
        count = sum(1 for f in self._must_fill_fields if getattr(self, f))
        return count

    @property
    def finish_percentage(self):
        return 100 * self.finished_fields_count // self.must_fill_fields_count

    @property
    def unfinished_fields_count(self):
        return self.must_fill_fields_count - self.finished_fields_count
示例#14
0
class UnidadeMedida(Nomeavel, TemChaveExterna):
    item = GenericRelation('ItemCadastro', related_query_name='unidade_medida')

    def __str__(self):
        return self.nome
示例#15
0
class Bookmark(models.Model):
    name = models.CharField(max_length=60)
    tag = GenericRelation(FunkyTag, related_query_name='bookmark')

    def __str__(self):
        return self.name
示例#16
0
class FriendRequest(models.Model):
    sender = models.ForeignKey(settings.AUTH_USER_MODEL,
                               on_delete=models.CASCADE,
                               related_name="sender")
    receiver = models.ForeignKey(settings.AUTH_USER_MODEL,
                                 on_delete=models.CASCADE,
                                 related_name="receiver")
    is_active = models.BooleanField(blank=True, null=False, default=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    notifications = GenericRelation(Notification)

    def __str__(self):
        return self.sender.username

    def accept(self):
        # Accepting the friend request
        receiver_friend_list = FriendList.objects.get(user=self.receiver)
        if receiver_friend_list:
            content_type = ContentType.objects.get_for_model(self)

            # Updating notification for RECEIVER
            receiver_notification = Notification.objects.get(
                target=self.receiver,
                content_type=content_type,
                object_id=self.id)
            receiver_notification.is_active = False
            receiver_notification.redirect_url = f"{settings.BASE_URL}/account/{self.sender.pk}/"
            receiver_notification.statement = f"You accepted {self.sender.username}'s friend request."
            receiver_notification.timestamp = timezone.now()
            receiver_notification.save()
            receiver_friend_list.add_friend(self.sender)

            sender_friend_list = FriendList.objects.get(user=self.sender)
            if sender_friend_list:
                # Create notification for SENDER
                self.notifications.create(
                    target=self.sender,
                    from_user=self.receiver,
                    redirect_url=
                    f"{settings.BASE_URL}/account/{self.receiver.pk}/",
                    statement=
                    f"{self.receiver.username} accepted your friend request.",
                    content_type=content_type,
                )

                sender_friend_list.add_friend(self.receiver)
                self.is_active = False
                self.save()
            return receiver_notification

    def decline(self):
        # Declining the friend request
        self.is_active = False
        self.save()

        content_type = ContentType.objects.get_for_model(self)

        # Update notification for RECEIVER
        notification = Notification.objects.get(target=self.receiver,
                                                content_type=content_type,
                                                object_id=self.id)
        notification.is_active = False
        notification.redirect_url = f"{settings.BASE_URL}/account/{self.sender.pk}/"
        notification.statement = f"You declined {self.sender}'s friend request."
        notification.from_user = self.sender
        notification.timestamp = timezone.now()
        notification.save()

        # Create notification for SENDER
        self.notifications.create(
            target=self.sender,
            statement=f"{self.receiver.username} declined your friend request.",
            from_user=self.receiver,
            redirect_url=f"{settings.BASE_URL}/account/{self.receiver.pk}/",
            content_type=content_type,
        )

        return notification

    def cancel(self):
        # Cancelling the request from the sender's perspective
        self.is_active = False
        self.save()

        content_type = ContentType.objects.get_for_model(self)

        # Create notification for SENDER
        self.notifications.create(
            target=self.sender,
            statement=
            f"You cancelled the friend request to {self.receiver.username}.",
            from_user=self.receiver,
            redirect_url=f"{settings.BASE_URL}/account/{self.receiver.pk}/",
            content_type=content_type,
        )

        notification = Notification.objects.get(target=self.receiver,
                                                content_type=content_type,
                                                object_id=self.id)
        notification.statement = f"{self.sender.username} cancelled the friend request sent to you."
        # notification.timestamp = timezone.now()
        notification.read = False
        notification.save()

    @property
    def get_cname(self):
        """
        For determining what kind of object is associated with a Notification
        """
        return "FriendRequest"
class Experience(models.Model):
    # In fact, a brick's experience consists not only user reviews,
    # but also applications of the brick.
    # This class only contains user reviews

    # According to iGem's websites, a user review has no title. We can make this optional.
    title = models.CharField(max_length=MAX_LEN_FOR_THREAD_TITLE,
                             blank=True,
                             default='')
    # experience can be uploaded by users, so use Article to support markdown.
    content = models.OneToOneField(Article,
                                   null=True,
                                   on_delete=models.SET_NULL,
                                   default=None)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               on_delete=models.CASCADE,
                               related_name='experience_set',
                               null=True,
                               default=None)
    # If the experience was uploaded by a user, the field author_name will be the username,
    # If the experience was fetched from the iGEM website,
    # the author_name should be set according to the data fetched.
    author_name = models.CharField(max_length=100, blank=True, default='')
    last_fetched = models.DateTimeField('last updated',
                                        null=True,
                                        default=None)
    # Automatically set the pub_time to now when the object is first created.
    # Also the pub_time can be set manually.
    pub_time = models.DateTimeField('publish time', auto_now_add=True)
    brick = models.ForeignKey('biobrick.BiobrickMeta',
                              on_delete=models.CASCADE,
                              null=True,
                              default=None,
                              related_name='experiences')
    votes = models.IntegerField(default=0)
    # add records for users mark down who has already voted for the post
    voted_users = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                         related_name='experiences_voted')

    activities = GenericRelation('forum.Activity',
                                 'target_id',
                                 'target_type',
                                 related_query_name='experience')
    notices = GenericRelation('notices.Notice',
                              'target_id',
                              'target_type',
                              related_query_name='experience')

    objects = ExperienceQuerySet.as_manager()

    def vote(self, user):

        from django.core.cache import cache
        from biohub.core.conf import settings as biohub_settings

        key = 'user_{}_vote'.format(user.id)
        if cache.get(key) is not None:
            raise Throttled()

        cache.set(key, 1, timeout=biohub_settings.THROTTLE['vote'])

        if self.author is not None and self.author.id == user.id:
            return False
        if not self.voted_users.filter(pk=user.id).exists():
            with transaction.atomic():
                self.votes += 1
                self.voted_users.add(user)
                self.save(update_fields=['votes'])
                voted_experience_signal.send(sender=self.__class__,
                                             instance=self,
                                             user_voted=user,
                                             current_votes=self.votes)
            return True
        return False

    def unvote(self, user):
        if self.voted_users.filter(pk=user.id).exists():
            with transaction.atomic():
                self.voted_users.remove(user)
                self.votes -= 1
                self.save(update_fields=['votes'])
                unvoted_experience_signal.send(sender=self.__class__,
                                               instance=self,
                                               user_unvoted=user)
            return True
        return False

    class Meta:
        ordering = ('-pub_time', 'id')

    def get_router_arguments(self):
        return 'experience', self.pk

    def __str__(self):
        return '%s' % self.title
示例#18
0
class ActionPoint(TimeStampedModel):
    MODULE_CHOICES = Choices(
        ('t2f', _('Trip Management')),
        ('tpm', 'Third Party Monitoring'),
        ('audit', _('Auditor Portal')),
    )

    STATUSES = Choices(
        ('open', _('Open')),
        ('completed', _('Completed')),
    )

    STATUSES_DATES = {
        STATUSES.open: 'created',
        STATUSES.completed: 'date_of_completion'
    }

    KEY_EVENTS = Choices(
        ('status_update', _('Status Update')),
        ('reassign', _('Reassign')),
    )

    author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='created_action_points',
                               verbose_name=_('Author'),
                               on_delete=models.CASCADE,
                               )
    assigned_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+', verbose_name=_('Assigned By'),
                                    on_delete=models.CASCADE,
                                    )
    assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='assigned_action_points',
                                    verbose_name=_('Assigned To'),
                                    on_delete=models.CASCADE,
                                    )

    status = FSMField(verbose_name=_('Status'), max_length=10, choices=STATUSES, default=STATUSES.open, protected=True)

    description = models.TextField(verbose_name=_('Description'))
    due_date = models.DateField(verbose_name=_('Due Date'), blank=True, null=True)
    high_priority = models.BooleanField(default=False, verbose_name=_('High Priority'))

    section = models.ForeignKey('reports.Sector', verbose_name=_('Section'), blank=True, null=True,
                                on_delete=models.CASCADE,
                                )
    office = models.ForeignKey('users.Office', verbose_name=_('Office'), blank=True, null=True,
                               on_delete=models.CASCADE,
                               )

    location = models.ForeignKey('locations.Location', verbose_name=_('Location'), blank=True, null=True,
                                 on_delete=models.CASCADE,
                                 )
    partner = models.ForeignKey('partners.PartnerOrganization', verbose_name=_('Partner'), blank=True, null=True,
                                on_delete=models.CASCADE,
                                )
    cp_output = models.ForeignKey('reports.Result', verbose_name=_('CP Output'), blank=True, null=True,
                                  on_delete=models.CASCADE,
                                  )
    intervention = models.ForeignKey('partners.Intervention', verbose_name=_('PD/SSFA'), blank=True, null=True,
                                     on_delete=models.CASCADE,
                                     )
    engagement = models.ForeignKey('audit.Engagement', verbose_name=_('Engagement'), blank=True, null=True,
                                   related_name='action_points', on_delete=models.CASCADE,
                                   )
    tpm_activity = models.ForeignKey('tpm.TPMActivity', verbose_name=_('TPM Activity'), blank=True, null=True,
                                     related_name='action_points', on_delete=models.CASCADE,
                                     )
    travel = models.ForeignKey('t2f.Travel', verbose_name=_('Travel'), blank=True, null=True,
                               on_delete=models.CASCADE,
                               )

    date_of_completion = MonitorField(verbose_name=_('Date Action Point Completed'), null=True, blank=True,
                                      default=None, monitor='status', when=[STATUSES.completed])

    comments = GenericRelation('django_comments.Comment', object_id_field='object_pk')

    history = GenericRelation('snapshot.Activity', object_id_field='target_object_id',
                              content_type_field='target_content_type')

    tracker = FieldTracker(fields=['assigned_to'])

    class Meta:
        ordering = ('id', )
        verbose_name = _('Action Point')
        verbose_name_plural = _('Action Points')

    @property
    def engagement_subclass(self):
        return self.engagement.get_subclass() if self.engagement else None

    @property
    def related_object(self):
        return self.engagement_subclass or self.tpm_activity or self.travel

    @property
    def related_module(self):
        if self.engagement:
            return self.MODULE_CHOICES.audit
        if self.tpm_activity:
            return self.MODULE_CHOICES.tpm
        if self.travel:
            return self.MODULE_CHOICES.t2f
        return None

    @property
    def reference_number(self):
        return '{}/{}/{}/APD'.format(
            connection.tenant.country_short_code or '',
            self.created.year,
            self.id,
        )

    def get_object_url(self, **kwargs):
        return build_frontend_url('apd', 'action-points', 'detail', self.id, **kwargs)

    @property
    def status_date(self):
        return getattr(self, self.STATUSES_DATES[self.status])

    def __str__(self):
        return self.reference_number

    def get_meaningful_history(self):
        return self.history.filter(
            models.Q(action=Activity.CREATE) |
            models.Q(models.Q(action=Activity.UPDATE), ~models.Q(change={}))
        )

    def snapshot_additional_data(self, diff):
        key_events = []
        if 'status' in diff:
            key_events.append(self.KEY_EVENTS.status_update)
        if 'assigned_to' in diff:
            key_events.append(self.KEY_EVENTS.reassign)

        return {'key_events': key_events}

    @classmethod
    def get_snapshot_action_display(cls, activity):
        key_events = activity.data.get('key_events')
        if key_events:
            if cls.KEY_EVENTS.status_update in key_events:
                return _('Changed status to {}').format(cls.STATUSES[activity.change['status']['after']])
            elif cls.KEY_EVENTS.reassign in key_events:
                return _('Reassigned to {}').format(
                    get_user_model().objects.get(pk=activity.change['assigned_to']['after']).get_full_name()
                )

        return activity.get_action_display()

    def get_mail_context(self, user=None, include_token=False):
        return {
            'person_responsible': self.assigned_to.get_full_name(),
            'assigned_by': self.assigned_by.get_full_name(),
            'reference_number': self.reference_number,
            'partner': self.partner.name if self.partner else '',
            'description': self.description,
            'due_date': self.due_date.strftime('%d %b %Y') if self.due_date else '',
            'object_url': self.get_object_url(user=user, include_token=include_token),
        }

    def send_email(self, recipient, template_name, additional_context=None):
        context = {
            'environment': get_environment(),
            'action_point': self.get_mail_context(user=recipient),
            'recipient': recipient.get_full_name(),
        }
        context.update(additional_context or {})

        notification = Notification.objects.create(
            sender=self,
            recipients=[recipient.email], template_name=template_name,
            template_data=context
        )
        notification.send_notification()

    def _do_complete(self):
        self.send_email(self.assigned_by, 'action_points/action_point/completed')

    @transition(status, source=STATUSES.open, target=STATUSES.completed,
                permission=has_action_permission(action='complete'),
                conditions=[
                    ActionPointCompleteActionsTakenCheck.as_condition()
                ])
    def complete(self):
        self._do_complete()
示例#19
0
class Task(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin,
           models.Model):
    user_story = models.ForeignKey("userstories.UserStory",
                                   null=True,
                                   blank=True,
                                   related_name="tasks",
                                   verbose_name=_("user story"))
    ref = models.BigIntegerField(db_index=True,
                                 null=True,
                                 blank=True,
                                 default=None,
                                 verbose_name=_("ref"))
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              null=True,
                              blank=True,
                              default=None,
                              related_name="owned_tasks",
                              verbose_name=_("owner"))
    status = models.ForeignKey("projects.TaskStatus",
                               null=True,
                               blank=True,
                               related_name="tasks",
                               verbose_name=_("status"))
    project = models.ForeignKey("projects.Project",
                                null=False,
                                blank=False,
                                related_name="tasks",
                                verbose_name=_("project"))
    milestone = models.ForeignKey("milestones.Milestone",
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL,
                                  default=None,
                                  related_name="tasks",
                                  verbose_name=_("milestone"))
    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"))
    finished_date = models.DateTimeField(null=True,
                                         blank=True,
                                         verbose_name=_("finished date"))
    subject = models.TextField(null=False,
                               blank=False,
                               verbose_name=_("subject"))

    us_order = models.IntegerField(null=False,
                                   blank=False,
                                   default=1,
                                   verbose_name=_("us order"))
    taskboard_order = models.IntegerField(null=False,
                                          blank=False,
                                          default=1,
                                          verbose_name=_("taskboard order"))

    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="tasks_assigned_to_me",
                                    verbose_name=_("assigned to"))
    attachments = GenericRelation("attachments.Attachment")
    is_iocaine = models.BooleanField(default=False,
                                     null=False,
                                     blank=True,
                                     verbose_name=_("is iocaine"))
    external_reference = TextArrayField(default=None,
                                        verbose_name=_("external reference"))
    _importing = None

    class Meta:
        verbose_name = "task"
        verbose_name_plural = "tasks"
        ordering = ["project", "created_date", "ref"]
        # unique_together = ("ref", "project")
        permissions = (("view_task", "Can view task"), )

    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_task_status

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

    def __str__(self):
        return "({1}) {0}".format(self.ref, self.subject)
示例#20
0
def enable_voting_on(cls, manager_name='objects',
                     votes_name='votes', upvotes_name='total_upvotes',
                     downvotes_name='total_downvotes', total_name='vote_total',
                     add_vote_name='add_vote', remove_vote_name='remove_vote',
                     base_manager=None):
    from django.contrib.contenttypes.models import ContentType
    from django.contrib.contenttypes.fields import GenericRelation
    from secretballot.models import Vote
    VOTE_TABLE = Vote._meta.db_table

    def add_vote(self, token, vote):
        voteobj, created = getattr(self, votes_name).get_or_create(token=token,
                                                                   defaults={
                                                                       'vote': vote,
                                                                       'content_object': self
                                                                   })
        if not created:
            voteobj.vote = vote
            voteobj.save()

    def remove_vote(self, token):
        getattr(self, votes_name).filter(token=token).delete()

    # gets added to the class as a property, not under this name
    def get_total(self):
        return getattr(self, upvotes_name) - getattr(self, downvotes_name)

    if base_manager is None:
        if hasattr(cls, manager_name):
            base_manager = getattr(cls, manager_name).__class__
        else:
            base_manager = Manager

    class VotableManager(base_manager):

        use_for_related_fields = True

        def get_queryset(self):
            db_table = self.model._meta.db_table
            pk_name = self.model._meta.pk.attname
            content_type = ContentType.objects.get_for_model(self.model).id
            downvote_query = '(SELECT COUNT(*) from %s WHERE vote=-1 AND object_id=%s.%s AND content_type_id=%s)' % (VOTE_TABLE, db_table, pk_name, content_type)
            upvote_query = '(SELECT COUNT(*) from %s WHERE vote=1 AND object_id=%s.%s AND content_type_id=%s)' % (VOTE_TABLE, db_table, pk_name, content_type)
            return super(VotableManager, self).get_queryset().extra(
                select={upvotes_name: upvote_query,
                        downvotes_name: downvote_query})

        def from_token(self, token):
            db_table = self.model._meta.db_table
            pk_name = self.model._meta.pk.attname
            content_type = ContentType.objects.get_for_model(self.model).id
            query = '(SELECT vote from %s WHERE token=%%s AND object_id=%s.%s AND content_type_id=%s)' % (VOTE_TABLE, db_table, pk_name, content_type)
            return self.get_queryset().extra(select={'user_vote': query}, select_params=(token,))

        def from_request(self, request):
            if not hasattr(request, 'secretballot_token'):
                raise ImproperlyConfigured('To use secretballot a SecretBallotMiddleware must '
                                           'be installed. (see secretballot/middleware.py)')
            return self.from_token(request.secretballot_token)

    cls.add_to_class('_default_manager', VotableManager())
    cls.add_to_class(manager_name, VotableManager())
    cls.add_to_class(votes_name, GenericRelation(Vote))
    cls.add_to_class(total_name, property(get_total))
    cls.add_to_class(add_vote_name, add_vote)
    cls.add_to_class(remove_vote_name, remove_vote)
    setattr(cls, '_secretballot_enabled', True)
示例#21
0
文件: models.py 项目: zengik/tabbycat
class Adjudicator(Person):
    institution = models.ForeignKey(Institution, models.SET_NULL, blank=True, null=True,
        verbose_name=_("institution"))
    # cascade to avoid unattached adjudicator pollution when deleting tournaments
    tournament = models.ForeignKey('tournaments.Tournament', models.CASCADE, blank=True, null=True,
        verbose_name=_("tournament"),
        help_text=_("Adjudicators not assigned to any tournament can be shared between tournaments"))
    base_score = models.FloatField(default=0,
        verbose_name=_("base score"))

    institution_conflicts = models.ManyToManyField('Institution',
        through='adjallocation.AdjudicatorInstitutionConflict',
        related_name='adj_inst_conflicts',
        verbose_name=_("institution conflicts"))
    team_conflicts = models.ManyToManyField('Team',
        through='adjallocation.AdjudicatorTeamConflict',
        related_name='adj_team_conflicts',
        verbose_name=_("team conflicts"))
    adjudicator_conflicts = models.ManyToManyField('Adjudicator',
        through='adjallocation.AdjudicatorAdjudicatorConflict',
        related_name='adj_adj_conflicts',
        verbose_name=_("adjudicator conflicts"))

    trainee = models.BooleanField(default=False,
        verbose_name=_("always trainee"),
        help_text=_("If checked, this adjudicator will never be auto-allocated a voting position, regardless of their score"))
    breaking = models.BooleanField(default=False,
        verbose_name=_("breaking"))
    independent = models.BooleanField(default=False, blank=True,
        verbose_name=_("independent"))
    adj_core = models.BooleanField(default=False, blank=True,
        verbose_name=_("adjudication core"))

    round_availabilities = GenericRelation('availability.RoundAvailability')
    venue_constraints = GenericRelation('venues.VenueConstraint', related_query_name='adjudicator',
            content_type_field='subject_content_type', object_id_field='subject_id')

    objects = AdjudicatorManager()

    class Meta:
        verbose_name = _("adjudicator")
        verbose_name_plural = _("adjudicators")

    def __str__(self):
        if self.institution is None:
            return self.name
        else:
            return "%s (%s)" % (self.name, self.institution.code)

    @property
    def region(self):
        return self.institution.region if self.institution else None

    def weighted_score(self, feedback_weight):
        feedback_score = self._feedback_score()
        if feedback_score is None:
            feedback_score = 0
            feedback_weight = 0
        return self.base_score * (1 - feedback_weight) + (feedback_weight * feedback_score)

    @cached_property
    def score(self):
        warn("Adjudicator.score is inefficient; consider using Adjudicator.weighted_score() instead.", stacklevel=2)
        if self.tournament:
            weight = self.tournament.current_round.feedback_weight
        else:
            weight = 1  # For shared ajudicators
        return self.weighted_score(weight)

    def _feedback_score(self):
        try:
            return self._feedback_score_cache
        except AttributeError:
            from adjallocation.models import DebateAdjudicator
            self._feedback_score_cache = self.adjudicatorfeedback_set.filter(confirmed=True, ignored=False).exclude(
                source_adjudicator__type=DebateAdjudicator.TYPE_TRAINEE).aggregate(
                    avg=models.Avg('score'))['avg']
            return self._feedback_score_cache

    @property
    def feedback_score(self):
        return self._feedback_score() or None

    def get_feedback(self):
        return self.adjudicatorfeedback_set.all()
示例#22
0
文件: models.py 项目: zengik/tabbycat
class Team(models.Model):
    reference = models.CharField(blank=True, max_length=150,
        verbose_name=_("full name/suffix"),
        help_text=_("Do not include institution name (see \"uses institutional prefix\" below)"))
    short_reference = models.CharField(blank=True, max_length=35,
        verbose_name=_("short name/suffix"),
        help_text=_("The name shown in the draw. Do not include institution name (see \"uses institutional prefix\" below)"))
    code_name = models.CharField(blank=True, max_length=150,
        verbose_name=_("code name"),
        help_text=_("Name used to obscure institutional identity on public-facing pages"))

    short_name = models.CharField(editable=False, max_length=20+1+35,  # Max institution code + space + short_reference max
        verbose_name=_("short name"),
        help_text=_("The name shown in the draw, including institution name. (This is autogenerated.)"))
    long_name = models.CharField(editable=False, max_length=100+1+150,  # Max institution name + space + reference max
        verbose_name=_("long name"),
        help_text=_("The full name of the team, including institution name. (This is autogenerated.)"))

    institution = models.ForeignKey(Institution, models.SET_NULL, blank=True, null=True,
        verbose_name=_("institution"))
    tournament = models.ForeignKey('tournaments.Tournament', models.CASCADE,
        verbose_name=_("tournament"))
    use_institution_prefix = models.BooleanField(default=False,
        verbose_name=_("Uses institutional prefix"),
        help_text=_("If ticked, a team called \"1\" from Victoria will be shown as \"Victoria 1\""))
    break_categories = models.ManyToManyField('breakqual.BreakCategory', blank=True,
        verbose_name=_("break categories"))

    institution_conflicts = models.ManyToManyField('Institution',
        through='adjallocation.TeamInstitutionConflict',
        related_name='team_inst_conflicts',
        verbose_name=_("institution conflicts"))

    round_availabilities = GenericRelation('availability.RoundAvailability')
    venue_constraints = GenericRelation('venues.VenueConstraint', related_query_name='team',
            content_type_field='subject_content_type', object_id_field='subject_id')

    TYPE_NONE = 'N'
    TYPE_SWING = 'S'
    TYPE_COMPOSITE = 'C'
    TYPE_BYE = 'B'
    TYPE_CHOICES = (
        (TYPE_NONE, _("none")),
        (TYPE_SWING, _("swing")),
        (TYPE_COMPOSITE, _("composite")),
        (TYPE_BYE, _("bye")),
    )
    type = models.CharField(max_length=1, choices=TYPE_CHOICES, default=TYPE_NONE,
        verbose_name=_("type"))

    emoji = models.CharField(max_length=2, default=None, choices=EMOJI_FIELD_CHOICES,
        blank=True, null=True,   # uses null=True to allow multiple teams to have no emoji
        verbose_name=_("emoji"))

    class Meta:
        unique_together = [
            # Enforce for blank references also - two teams from the same
            # institution can't both be unlabelled. However, Django won't
            # enforce this for null institutions.
            ('reference', 'institution', 'tournament'),

            # Not enforced for blank emoji (null=True is set on emoji)
            ('emoji', 'tournament'),
        ]
        ordering = ['tournament', 'institution', 'short_reference']
        index_together = ['tournament', 'institution', 'short_reference']
        verbose_name = _("team")
        verbose_name_plural = _("teams")

    objects = TeamManager()

    def __str__(self):
        return "[{}] {}".format(self.tournament.slug, self.short_name)

    def _construct_short_name(self):
        institution = self.institution
        reference = self.short_reference or self.reference
        if self.use_institution_prefix and institution is not None:
            short_name = institution.code
            if reference:
                short_name += " " + str(reference)[:35]
            return short_name
        else:
            return str(reference)[:20+1+35]

    def _construct_long_name(self):
        institution = self.institution
        if self.use_institution_prefix and institution is not None:
            long_name = institution.name
            if self.reference:
                long_name += " " + self.reference
            return long_name
        else:
            return self.reference

    @property
    def region(self):
        return self.institution.region if self.institution else None

    def break_rank_for_category(self, category):
        from breakqual.models import BreakingTeam
        try:
            bt = BreakingTeam.objects.get(break_category=category, team=self)
        except BreakingTeam.DoesNotExist:
            return None
        return bt.break_rank

    def get_debates(self, before_round):
        dts = self.debateteam_set.select_related('debate').order_by(
            'debate__round__seq')
        if before_round is not None:
            dts = dts.filter(debate__round__seq__lt=before_round)
        return [dt.debate for dt in dts]

    @property
    def debates(self):
        return self.get_debates(None)

    @property
    def wins_count(self):
        """Callers using this property for many teams should prefetch them
        using `populate_win_counts()` in the `participants.prefetch` module."""
        try:
            return self._wins_count
        except AttributeError:
            from results.models import TeamScore
            self._wins_count = TeamScore.objects.filter(ballot_submission__confirmed=True,
                    debate_team__team=self, win=True).count()
            return self._wins_count

    @property
    def points_count(self):
        """Callers using this property for many teams should prefetch them
        using `populate_win_counts()` in the `participants.prefetch` module.
        (That's not a typo -- that function populates both `_wins_count` and
        `_points`.)"""
        try:
            return self._points
        except AttributeError:
            from results.models import TeamScore
            self._points = TeamScore.objects.filter(ballot_submission__confirmed=True,
                    debate_team__team=self).aggregate(Sum('points'))['points__sum']
            return self._points

    @cached_property
    def speakers(self):
        return self.speaker_set.all()

    def seen(self, other, before_round=None):
        queryset = self.debateteam_set.filter(debate__debateteam__team=other)
        if before_round:
            queryset = queryset.filter(debate__round__seq__lt=before_round)
        return queryset.count()

    def same_institution(self, other):
        """Returns True if this team and `other` are from the same institution.
        Always returns False if this team has no institution."""
        return self.institution_id is not None and self.institution_id == other.institution_id

    def prev_debate(self, round_seq):
        from draw.models import DebateTeam
        try:
            return DebateTeam.objects.filter(
                debate__round__seq__lt=round_seq,
                team=self).order_by('-debate__round__seq')[0].debate
        except IndexError:
            return None

    def clean(self):
        # Require reference and short_reference if use_institution_prefix is False
        errors = {}
        if self.use_institution_prefix and self.institution is None:
            errors['institution'] = _("Teams must have an institution if they are using the institutional prefix.")
        if not self.use_institution_prefix and not self.reference:
            errors['reference'] = _("Teams must have a full name if they don't use the institutional prefix.")
        if not self.use_institution_prefix and not self.short_reference:
            errors['short_reference'] = _("Teams must have a short name if they don't use the institutional prefix.")
        if errors:
            raise ValidationError(errors)

    def save(self, *args, **kwargs):
        # Override the short and long names before saving
        self.short_name = self._construct_short_name()
        self.long_name = self._construct_long_name()
        super().save(*args, **kwargs)
示例#23
0
class Creator(GcdData):
    class Meta:
        app_label = 'gcd'
        ordering = ('sort_name', 'created',)
        verbose_name_plural = 'Creators'

    objects = CreatorManager()

    gcd_official_name = models.CharField(max_length=255, db_index=True)
    sort_name = models.CharField(max_length=255, db_index=True, default='')
    disambiguation = models.CharField(max_length=255, default='',
                                      db_index=True)

    birth_date = models.ForeignKey(Date, on_delete=models.CASCADE,
                                   related_name='+', null=True)
    death_date = models.ForeignKey(Date, on_delete=models.CASCADE,
                                   related_name='+', null=True)

    whos_who = models.URLField(null=True)

    birth_country = models.ForeignKey(Country, on_delete=models.CASCADE,
                                      related_name='birth_country',
                                      null=True)
    birth_country_uncertain = models.BooleanField(default=False)
    birth_province = models.CharField(max_length=50)
    birth_province_uncertain = models.BooleanField(default=False)
    birth_city = models.CharField(max_length=200)
    birth_city_uncertain = models.BooleanField(default=False)

    death_country = models.ForeignKey(Country, on_delete=models.CASCADE,
                                      related_name='death_country',
                                      null=True)
    death_country_uncertain = models.BooleanField(default=False)
    death_province = models.CharField(max_length=50)
    death_province_uncertain = models.BooleanField(default=False)
    death_city = models.CharField(max_length=200)
    death_city_uncertain = models.BooleanField(default=False)

    portrait = GenericRelation(Image)
    awards = GenericRelation(ReceivedAward)

    bio = models.TextField()
    sample_scan = GenericRelation(Image)
    notes = models.TextField()

    data_source = models.ManyToManyField(DataSource)

    def _portrait(self):
        content_type = ContentType.objects.get_for_model(self)
        img = Image.objects.filter(object_id=self.id, deleted=False,
                                   content_type=content_type, type__id=4)
        if img:
            return img.get()
        else:
            return None

    portrait = property(_portrait)

    def _samplescan(self):
        content_type = ContentType.objects.get_for_model(self)
        img = Image.objects.filter(object_id=self.id, deleted=False,
                                   content_type=content_type, type__id=5)
        if img:
            return img.get()
        else:
            return None

    samplescan = property(_samplescan)

    def full_name(self):
        return str(self)

    def display_birthday(self):
        return _display_day(self.birth_date)

    def display_birthplace(self):
        return _display_place(self, 'birth')

    def display_deathday(self):
        return _display_day(self.death_date)

    def display_deathplace(self):
        return _display_place(self, 'death')

    def has_death_info(self):
        if str(self.death_date) != '':
            return True
        else:
            return False

    def has_dependents(self):
        if self.creator_names.filter(storycredit__deleted=False).exists():
            return True
        if self.art_influence_revisions.active_set().exists():
            return True
        # TODO how to handle GenericRelation for ReceivedAward
        # if self.award_revisions.filter.active_set().count():
            # return True
        if self.degree_revisions.active_set().exists():
            return True
        if self.membership_revisions.active_set().exists():
            return True
        if self.non_comic_work_revisions.active_set().exists():
            return True
        if self.school_revisions.active_set().exists():
            return True
        if self.active_relations().exists():
            return True
        if self.active_influenced_creators().exists():
            return True

        return False

    def active_names(self):
        return self.creator_names.exclude(deleted=True)

    def active_art_influences(self):
        return self.art_influences.exclude(deleted=True)\
                   .order_by('influence_link__sort_name', 'influence_name')

    def active_influenced_creators(self):
        return self.influenced_creators.exclude(deleted=True)\
                   .order_by('creator__sort_name')

    def active_awards(self):
        return self.awards.exclude(deleted=True)

    def active_awards_for_issues(self):
        from .issue import Issue
        issues = Issue.objects.filter(story__credits__creator__creator=self,
                                      awards__isnull=False).distinct()
        content_type = ContentType.objects.get(model='Issue')
        awards = ReceivedAward.objects.filter(content_type=content_type,
                                              object_id__in=issues)
        return awards

    def active_awards_for_stories(self):
        from .story import Story
        stories = Story.objects.filter(credits__creator__creator=self,
                                       awards__isnull=False).distinct()
        content_type = ContentType.objects.get(model='Story')
        awards = ReceivedAward.objects.filter(content_type=content_type,
                                              object_id__in=stories)
        return awards

    def active_degrees(self):
        return self.degree_set.exclude(deleted=True)

    def active_memberships(self):
        return self.membership_set.exclude(deleted=True)

    def active_non_comic_works(self):
        return self.non_comic_work_set.exclude(deleted=True)

    def active_relations(self):
        return self.from_related_creator.exclude(deleted=True) | \
               self.to_related_creator.exclude(deleted=True)

    def active_schools(self):
        return self.school_set.exclude(deleted=True)

    def active_signatures(self):
        return self.signatures.exclude(deleted=True)

    _update_stats = True

    def stat_counts(self):
        """
        Returns all count values relevant to this creator.
        """
        if self.deleted:
            return {}

        return {'creators': 1}

    def get_absolute_url(self):
        return urlresolvers.reverse(
                'show_creator',
                kwargs={'creator_id': self.id})

    def __str__(self):
        if self.birth_date.year:
            year = '(b. %s)' % self.birth_date.year
        else:
            year = ''
        return '%s %s' % (str(self.gcd_official_name), year)
示例#24
0
class Directory(TendenciBaseModel):

    guid = models.CharField(max_length=40)
    slug = SlugField(_('URL Path'), unique=True)
    timezone = TimeZoneField(_('Time Zone'))
    headline = models.CharField(_('Name'), max_length=200, blank=True)
    summary = models.TextField(blank=True)
    body = tinymce_models.HTMLField(_('Description'))
    source = models.CharField(max_length=300, blank=True)
    # logo = models.FileField(max_length=260, upload_to=file_directory,
    #                         help_text=_('Company logo. Only jpg, gif, or png images.'),
    #                         blank=True)

    logo_file = models.ForeignKey(File, null=True)

    first_name = models.CharField(_('First Name'), max_length=100, blank=True)
    last_name = models.CharField(_('Last Name'), max_length=100, blank=True)
    address = models.CharField(_('Address'), max_length=100, blank=True)
    address2 = models.CharField(_('Address 2'), max_length=100, blank=True)
    city = models.CharField(_('City'), max_length=50, blank=True)
    state = models.CharField(_('State'), max_length=50, blank=True)
    zip_code = models.CharField(_('Zip Code'), max_length=50, blank=True)
    country = models.CharField(_('Country'), max_length=50, blank=True)
    phone = models.CharField(max_length=50, blank=True)
    phone2 = models.CharField(_('Phone 2'), max_length=50, blank=True)
    fax = models.CharField(_('Fax'), max_length=50, blank=True)
    email = models.CharField(_('Email'), max_length=120, blank=True)
    email2 = models.CharField(_('Email 2'), max_length=120, blank=True)
    website = models.CharField(max_length=300, blank=True)

    renewal_notice_sent = models.BooleanField(default=False)
    list_type = models.CharField(_('List Type'), max_length=50, blank=True)
    requested_duration = models.IntegerField(_('Requested Duration'), default=0)
    pricing = models.ForeignKey('DirectoryPricing', null=True)
    activation_dt = models.DateTimeField(_('Activation Date/Time'), null=True, blank=True)
    expiration_dt = models.DateTimeField(_('Expiration Date/Time'), null=True, blank=True)
    invoice = models.ForeignKey(Invoice, blank=True, null=True)
    payment_method = models.CharField(_('Payment Method'), max_length=50, blank=True)

    syndicate = models.BooleanField(_('Include in RSS feed'), default=True)
    design_notes = models.TextField(_('Design Notes'), blank=True)
    admin_notes = models.TextField(_('Admin Notes'), blank=True)
    tags = TagField(blank=True)

    # for podcast feeds
    enclosure_url = models.CharField(_('Enclosure URL'), max_length=500, blank=True)
    enclosure_type = models.CharField(_('Enclosure Type'), max_length=120, blank=True)
    enclosure_length = models.IntegerField(_('Enclosure Length'), default=0)

    # html-meta tags
    meta = models.OneToOneField(MetaTags, null=True)

    cat = models.ForeignKey(Category, verbose_name=_("Category"),
                                 related_name="directory_cat", null=True, on_delete=models.SET_NULL)
    sub_cat = models.ForeignKey(Category, verbose_name=_("Sub Category"),
                                 related_name="directory_subcat", null=True, on_delete=models.SET_NULL)
    # legacy categories needed for data migration
    categories = GenericRelation(CategoryItem,
                                          object_id_field="object_id",
                                          content_type_field="content_type")
    perms = GenericRelation(ObjectPermission,
                                          object_id_field="object_id",
                                          content_type_field="content_type")

    objects = DirectoryManager()

    class Meta:
        permissions = (("view_directory",_("Can view directory")),)
        verbose_name = _("Directory")
        verbose_name_plural = _("Directories")
        app_label = 'directories'

    def get_meta(self, name):
        """
        This method is standard across all models that are
        related to the Meta model.  Used to generate dynamic
        methods coupled to this instance.
        """
        return DirectoryMeta().get_meta(self, name)

    @models.permalink
    def get_absolute_url(self):
        return ("directory", [self.slug])

    @models.permalink
    def get_renew_url(self):
        return ("directory.renew", [self.id])

    def __unicode__(self):
        return self.headline

    def save(self, *args, **kwargs):
        if not self.id:
            self.guid = str(uuid.uuid1())

        super(Directory, self).save(*args, **kwargs)
        if self.logo:
            if self.is_public():
                set_s3_file_permission(self.logo.name, public=True)
            else:
                set_s3_file_permission(self.logo.name, public=False)

    def is_public(self):
        return all([self.allow_anonymous_view,
                self.status,
                self.status_detail in ['active']])

    @property
    def logo(self):
        """
        This represents the logo FileField

        Originally this was a FileField, but later
        we added the attribute logo_file to leverage
        the File model.  We then replaced the logo
        property with this convience method for
        backwards compatibility.
        """
        if self.logo_file:
            return self.logo_file.file

    def get_logo_url(self):
        if not self.logo_file:
            return u''

        return reverse('file', args=[self.logo_file.pk])

    # Called by payments_pop_by_invoice_user in Payment model.
    def get_payment_description(self, inv):
        """
        The description will be sent to payment gateway and displayed on invoice.
        If not supplied, the default description will be generated.
        """
        return 'Tendenci Invoice %d for Directory: %s (%d).' % (
            inv.id,
            self.headline,
            inv.object_id,
        )

    def make_acct_entries(self, user, inv, amount, **kwargs):
        """
        Make the accounting entries for the directory sale
        """
        from tendenci.apps.accountings.models import Acct, AcctEntry, AcctTran
        from tendenci.apps.accountings.utils import make_acct_entries_initial, make_acct_entries_closing

        ae = AcctEntry.objects.create_acct_entry(user, 'invoice', inv.id)
        if not inv.is_tendered:
            make_acct_entries_initial(user, ae, amount)
        else:
            # payment has now been received
            make_acct_entries_closing(user, ae, amount)

            # #CREDIT directory SALES
            acct_number = self.get_acct_number()
            acct = Acct.objects.get(account_number=acct_number)
            AcctTran.objects.create_acct_tran(user, ae, acct, amount*(-1))

    def get_acct_number(self, discount=False):
        if discount:
            return 464400
        else:
            return 404400

    def auto_update_paid_object(self, request, payment):
        """
        Update the object after online payment is received.
        """
        if not request.user.profile.is_superuser:
            self.status_detail = 'paid - pending approval'
            self.save()

    def age(self):
        return datetime.now() - self.create_dt

    @property
    def category_set(self):
        items = {}
        for cat in self.categories.select_related('category__name', 'parent__name'):
            if cat.category:
                items["category"] = cat.category
            elif cat.parent:
                items["sub_category"] = cat.parent
        return items

    def renew_window(self):
        days = get_setting('module', 'directories', 'renewaldays')
        days = int(days)
        if self.expiration_dt and datetime.now() + timedelta(days) > self.expiration_dt:
            return True
        else:
            return False
示例#25
0
class LotMixin(models.Model):
    BOROUGH_CHOICES = (
        ('Bronx', 'Bronx'),
        ('Brooklyn', 'Brooklyn'),
        ('Manhattan', 'Manhattan'),
        ('Queens', 'Queens'),
        ('Staten Island', 'Staten Island'),
    )

    accessible = models.BooleanField(default=True)
    bbl = models.CharField(max_length=10, blank=True, null=True)
    block = models.IntegerField(blank=True, null=True)
    borough = models.CharField(max_length=25, choices=BOROUGH_CHOICES)
    gutterspace = models.BooleanField(default=False)
    lot_number = models.IntegerField(blank=True, null=True)
    organizers = GenericRelation(Organizer)
    organizing = models.BooleanField(default=False)
    parcel = models.ForeignKey(
        'parcels.Parcel',
        blank=True,
        null=True,
    )

    commons_content_type = models.ForeignKey(ContentType, null=True)
    commons_object_id = models.PositiveIntegerField(null=True)
    commons_content_object = GenericForeignKey('commons_content_type',
                                               'commons_object_id')
    commons_type = models.CharField(max_length=25, choices=COMMONS_TYPES)
    priority = models.BooleanField(
        default=False,
        verbose_name=_('Development pending'),
    )
    development_pending_explanation = tinymce_models.HTMLField(
        blank=True,
        null=True,
        help_text=_(
            'If development is pending, let visitors to the site know why.'),
    )

    files = GenericRelation('files.File')
    groundtruth_records = GenericRelation('groundtruth.GroundtruthRecord')
    notes = GenericRelation('notes.Note')
    photos = GenericRelation('photos.Photo')
    steward_notifications = GenericRelation('steward.StewardNotification')
    steward_projects = GenericRelation('steward.StewardProject')

    owner_opt_in = models.BooleanField(default=False)

    def _get_display_name(self):
        if self.name:
            return self.name
        if self.bbl_is_fake:
            if self.address_line1:
                return self.address_line1
            return '%s, unmapped lot #%d' % (self.borough, self.lot_number)
        try:
            return '%s block %d, lot %d' % (self.borough, self.block,
                                            self.lot_number)
        except TypeError:
            try:
                blocks = list(set([l.block for l in self.lots]))
                block_strs = []
                for block in sorted(blocks):
                    block_lots = [l for l in self.lots if l.block == block]
                    block_strs.append('block %d, %s' % (block, '%s %s' % (
                        'lot' if len(block_lots) == 1 else 'lots',
                        ', '.join(
                            sorted([str(l.lot_number) for l in block_lots])),
                    )))
                return '%s %s' % (self.borough, '; '.join(block_strs))
            except TypeError:
                return self.address_line1

    display_name = property(_get_display_name)

    @classmethod
    def get_filter(cls):
        from .filters import LotFilter
        return LotFilter

    def calculate_polygon_area(self):
        try:
            return self.polygon.transform(2263, clone=True).area
        except Exception:
            return None

    def _area(self):
        if not self.polygon_area:
            try:
                # Try to get area from parcel's PLUTO data
                self.polygon_area = self.parcel.lotarea
            except Exception:
                self.polygon_area = self.calculate_polygon_area()
            self.save()
        return self.polygon_area

    area = property(_area)

    def _area_acres(self):
        try:
            area = self.area * (ureg.feet**2)
            return area.to(ureg.acre).magnitude
        except (ValueError, TypeError):
            return None

    area_acres = property(_area_acres)

    def _bbl_is_fake(self):
        return self.bbl and self.bbl.startswith('6')

    bbl_is_fake = property(_bbl_is_fake)

    def _owners(self):
        owners = [
            self.owner,
        ] + [l.owner for l in self.lots]
        return [o for o in set(owners) if o]

    owners = property(_owners)

    def _owner_contacts(self):
        contacts = [
            self.owner_contact,
        ]
        contacts += [l.owner_contact for l in self.lots]

        for l in self.lots:
            if not l.owner:
                continue
            if l.owner.default_contact:
                contacts.append(l.owner.default_contact)
            elif l.owner.ownercontact_set.count() == 1:
                contacts.append(l.owner.ownercontact_set.all()[0])

        # Dedupe while keeping correct order
        return sorted(list(set(filter(None, contacts))), key=contacts.index)

    owner_contacts = property(_owner_contacts)

    def get_owner_contact(self):
        if self.owner_contact:
            return self.owner_contact
        if len(self.owner_contacts) == 1:
            return self.owner_contacts[0]

    def _bbox(self):
        try:
            return list(self.polygon.extent)
        except Exception:
            return list(self.centroid.buffer(.0005).extent)

    bbox = property(_bbox)

    def _get_lots(self):
        try:
            return self.lotgroup.lot_set.all().order_by('block', 'lot_number')
        except Exception:
            return [
                self,
            ]

    lots = property(_get_lots)

    def get_new_lotgroup_kwargs(self):
        kwargs = super(LotMixin, self).get_new_lotgroup_kwargs()
        kwargs.update({
            'borough': self.borough,
            'commons_type': self.commons_type,
            'known_use': self.known_use,
            'known_use_certainty': self.known_use_certainty,
            'known_use_locked': self.known_use_locked,
            'steward_inclusion_opt_in': self.steward_inclusion_opt_in,
            'owner': self.owner,
            'owner_opt_in': self.owner_opt_in,
        })
        return kwargs

    def reassign_objects(self, new_lot, **kwargs):
        """Reassign related objects (eg, notes or organizers) to the new lot"""
        self.files.update(**kwargs)

        self.notes.update(**kwargs)
        self.organizers.update(**kwargs)
        self.photos.update(**kwargs)
        self.steward_projects.update(**kwargs)

        # Handle things with MonitorEntrys (moderated)
        monitor_objs = (list(self.groundtruth_records.all()) +
                        list(self.steward_notifications.all()))
        for obj in monitor_objs:
            obj.content_object = new_lot
            obj.save()

    def __unicode__(self):
        if self.display_name:
            return self.display_name
        return u'%d' % self.pk

    class Meta:
        abstract = True
示例#26
0
class Member(TimeStampedModel):
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    STATUS = Choices(
        (
            -10,
            'inactive',
            'Inactive',
        ),
        (
            0,
            'new',
            'New',
        ),
        (
            10,
            'active',
            'Active',
        ),
    )

    status = FSMIntegerField(
        help_text=
        """DO NOT CHANGE MANUALLY unless correcting a mistake.  Use the buttons to change state.""",
        choices=STATUS,
        default=STATUS.new,
    )

    # MEM_STATUS = Choices(
    #     (10, 'active', 'Active',),
    #     (20, 'active_internal', 'Active Internal',),
    #     (30, 'active_licensed', 'Active Licensed',),
    #     (40, 'cancelled', 'Cancelled',),
    #     (50, 'closed', 'Closed',),
    #     (60, 'closed_merged', 'Closed Merged',),
    #     (70, 'closed_revoked', 'Closed Revoked',),
    #     (80, 'closed_voluntary', 'Closed Voluntary',),
    #     (90, 'expelled', 'Expelled',),
    #     (100, 'expired', 'Expired',),
    #     (105, 'expired_licensed', 'Expired Licensed',),
    #     (110, 'lapsed', 'Lapsed',),
    #     (120, 'not_approved', 'Not Approved',),
    #     (130, 'pending', 'Pending',),
    #     (140, 'pending_voluntary', 'Pending Voluntary',),
    #     (150, 'suspended', 'Suspended',),
    #     (160, 'suspended_membership', 'Suspended Membership',),
    #     (170, 'awaiting_payment', 'Awaiting Payment',),
    # )

    # mem_status = models.IntegerField(
    #     choices=MEM_STATUS,
    #     null=True,
    #     blank=True,
    # )

    # SUB_STATUS = Choices(
    #     (10, 'active', 'Active',),
    #     (20, 'expired', 'Expired',),
    #     (30, 'pending', 'Pending',),
    #     (40, 'lapsedRenew', 'Lapsed',),
    #     (50, 'cancelled', 'Cancelled',),
    #     (60, 'swapped', 'Swapped',),
    # )

    # sub_status = models.IntegerField(
    #     choices=SUB_STATUS,
    #     null=True,
    #     blank=True,
    # )

    # MEM_CODE = Choices(
    #     (10, 'RG', 'RG Regular'),
    #     (20, 'R5', 'R5 Regular 50 Year'),
    #     (30, 'SN', 'SN Senior'),
    #     (40, 'S5', 'S5 Senior 50 Year'),
    #     (50, 'SL', 'SL Senior Legacy'),
    #     (60, 'Y1', 'Y1 Youth Initial'),
    #     (70, 'Y2', 'Y2 Youth Subsequent'),
    #     (80, 'LF', 'LF Lifetime Regular'),
    #     (90, 'L5', 'L5 Lifetime 50 Year'),
    #     (100, 'LY', 'LY Lifetime Youth'),
    #     (110, 'LS', 'LS Lifetime Senior'),
    #     (120, 'AS', 'AS Associate'),
    # )

    # mem_code = models.IntegerField(
    #     choices=MEM_CODE,
    #     null=True,
    #     blank=True,
    # )

    # inactive_date = models.DateField(
    #     null=True,
    #     blank=True,
    # )

    # INACTIVE_REASON = Choices(
    #     (1, 'Non_renewal', 'Non-Renewal'),
    #     (2, 'Renewed', 'Renewed'),
    #     (3, 'NotCancelled', 'Not Cancelled'),
    #     (4, 'Non_Payment', 'Non-Payment'),
    #     (5, 'Expired', 'Expired'),
    #     (6, 'Deceased', 'Deceased'),
    #     (7, 'changedOption', 'changedOption'),
    #     (8, 'Other', 'Other'),
    #     (9, 'cancelled', 'cancelled'),
    #     (10, 'Transferred', 'Transferred'),
    #     (11, 'swappedChapter', 'swappedChapter'),
    #     (12, 'swapped', 'swapped'),
    # )

    # inactive_reason = models.IntegerField(
    #     choices=INACTIVE_REASON,
    #     null=True,
    #     blank=True,
    # )

    PART = Choices(
        # (-1, 'director', 'Director'),
        (1, 'tenor', 'Tenor'),
        (2, 'lead', 'Lead'),
        (3, 'baritone', 'Baritone'),
        (4, 'bass', 'Bass'),
    )

    part = models.IntegerField(
        choices=PART,
        null=True,
        blank=True,
    )

    start_date = models.DateField(
        null=True,
        blank=True,
    )

    end_date = models.DateField(
        null=True,
        blank=True,
    )

    mc_pk = models.CharField(
        null=True,
        blank=True,
        max_length=36,
        unique=True,
        db_index=True,
    )

    # Properties
    @cached_property
    def is_mc(self):
        return bool(self.mc_pk)

    # FKs
    group = models.ForeignKey(
        'Group',
        related_name='members',
        on_delete=models.CASCADE,
    )

    person = models.ForeignKey(
        'Person',
        related_name='members',
        on_delete=models.CASCADE,
    )

    # Relations
    statelogs = GenericRelation(
        StateLog,
        related_query_name='members',
    )

    # Internals
    objects = MemberManager()

    class Meta:
        unique_together = ((
            'group',
            'person',
        ), )

    class JSONAPIMeta:
        resource_name = "member"

    def __str__(self):
        return str(self.id)

    def clean(self):
        if all([
                self.status == self.STATUS.active,
                self.person.status == self.person.STATUS.inactive,
        ]):
            raise ValidationError({
                'status':
                'Can not be active when person is inactive',
            })
        if self.end_date:
            if all([
                    self.status == self.STATUS.active,
                    self.end_date < now().date(),
            ]):
                raise ValidationError({
                    'status':
                    'Can not be active with a passed end date',
                })

    # Permissions
    @staticmethod
    @allow_staff_or_superuser
    @authenticated_users
    def has_read_permission(request):
        return True

    @allow_staff_or_superuser
    @authenticated_users
    def has_object_read_permission(self, request):
        return True

    @staticmethod
    @allow_staff_or_superuser
    @authenticated_users
    def has_write_permission(request):
        return any([
            request.user.is_group_manager,
        ])

    @allow_staff_or_superuser
    @authenticated_users
    def has_object_write_permission(self, request):
        return any([
            all([
                self.group.officers.filter(
                    person__user=request.user,
                    status__gt=0,
                ),
                self.mc_pk == None,
            ]),
        ])

    # Transitions
    @fsm_log_by
    @fsm_log_description
    @transition(field=status, source='*', target=STATUS.active)
    def activate(self, description=None, *args, **kwargs):
        """Activate the Member."""
        return

    @fsm_log_by
    @fsm_log_description
    @transition(field=status, source='*', target=STATUS.inactive)
    def deactivate(self, description=None, *args, **kwargs):
        """Deactivate the Member."""
        return
示例#27
0
文件: models.py 项目: yuta2/netbox
class Aggregate(ChangeLoggedModel, CustomFieldModel):
    """
    An aggregate exists at the root level of the IP address space hierarchy in NetBox. Aggregates are used to organize
    the hierarchy and track the overall utilization of available address space. Each Aggregate is assigned to a RIR.
    """
    family = models.PositiveSmallIntegerField(
        choices=IPAddressFamilyChoices
    )
    prefix = IPNetworkField()
    rir = models.ForeignKey(
        to='ipam.RIR',
        on_delete=models.PROTECT,
        related_name='aggregates',
        verbose_name='RIR'
    )
    date_added = models.DateField(
        blank=True,
        null=True
    )
    description = models.CharField(
        max_length=100,
        blank=True
    )
    custom_field_values = GenericRelation(
        to='extras.CustomFieldValue',
        content_type_field='obj_type',
        object_id_field='obj_id'
    )

    tags = TaggableManager(through=TaggedItem)

    csv_headers = ['prefix', 'rir', 'date_added', 'description']
    clone_fields = [
        'rir', 'date_added', 'description',
    ]

    class Meta:
        ordering = ('family', 'prefix', 'pk')  # (family, prefix) may be non-unique

    def __str__(self):
        return str(self.prefix)

    def get_absolute_url(self):
        return reverse('ipam:aggregate', args=[self.pk])

    def clean(self):

        if self.prefix:

            # Clear host bits from prefix
            self.prefix = self.prefix.cidr

            # /0 masks are not acceptable
            if self.prefix.prefixlen == 0:
                raise ValidationError({
                    'prefix': "Cannot create aggregate with /0 mask."
                })

            # Ensure that the aggregate being added is not covered by an existing aggregate
            covering_aggregates = Aggregate.objects.filter(prefix__net_contains_or_equals=str(self.prefix))
            if self.pk:
                covering_aggregates = covering_aggregates.exclude(pk=self.pk)
            if covering_aggregates:
                raise ValidationError({
                    'prefix': "Aggregates cannot overlap. {} is already covered by an existing aggregate ({}).".format(
                        self.prefix, covering_aggregates[0]
                    )
                })

            # Ensure that the aggregate being added does not cover an existing aggregate
            covered_aggregates = Aggregate.objects.filter(prefix__net_contained=str(self.prefix))
            if self.pk:
                covered_aggregates = covered_aggregates.exclude(pk=self.pk)
            if covered_aggregates:
                raise ValidationError({
                    'prefix': "Aggregates cannot overlap. {} covers an existing aggregate ({}).".format(
                        self.prefix, covered_aggregates[0]
                    )
                })

    def save(self, *args, **kwargs):
        if self.prefix:
            # Infer address family from IPNetwork object
            self.family = self.prefix.version
        super().save(*args, **kwargs)

    def to_csv(self):
        return (
            self.prefix,
            self.rir.name,
            self.date_added,
            self.description,
        )

    def get_utilization(self):
        """
        Determine the prefix utilization of the aggregate and return it as a percentage.
        """
        queryset = Prefix.objects.filter(prefix__net_contained_or_equal=str(self.prefix))
        child_prefixes = netaddr.IPSet([p.prefix for p in queryset])
        return int(float(child_prefixes.size) / self.prefix.size * 100)
示例#28
0
class Issue(GcdData):
    class Meta:
        app_label = 'gcd'
        ordering = ['series', 'sort_code']
        unique_together = ('series', 'sort_code')

    # Issue identification
    number = models.CharField(max_length=50, db_index=True)
    title = models.CharField(max_length=255, db_index=True)
    no_title = models.BooleanField(default=False, db_index=True)
    volume = models.CharField(max_length=50, db_index=True)
    no_volume = models.BooleanField(default=False, db_index=True)
    volume_not_printed = models.BooleanField(default=False)
    display_volume_with_number = models.BooleanField(default=False,
                                                     db_index=True)
    isbn = models.CharField(max_length=32, db_index=True)
    no_isbn = models.BooleanField(default=False, db_index=True)
    valid_isbn = models.CharField(max_length=13, db_index=True)
    variant_of = models.ForeignKey('self',
                                   on_delete=models.CASCADE,
                                   null=True,
                                   related_name='variant_set')
    variant_name = models.CharField(max_length=255)
    barcode = models.CharField(max_length=38, db_index=True)
    no_barcode = models.BooleanField(default=False)
    rating = models.CharField(max_length=255, default='', db_index=True)
    no_rating = models.BooleanField(default=False, db_index=True)

    # Dates and sorting
    publication_date = models.CharField(max_length=255)
    key_date = models.CharField(max_length=10, db_index=True)
    on_sale_date = models.CharField(max_length=10, db_index=True)
    on_sale_date_uncertain = models.BooleanField(default=False)
    sort_code = models.IntegerField(db_index=True)
    indicia_frequency = models.CharField(max_length=255)
    no_indicia_frequency = models.BooleanField(default=False, db_index=True)

    # Price, page count and format fields
    price = models.CharField(max_length=255)
    page_count = models.DecimalField(max_digits=10,
                                     decimal_places=3,
                                     null=True)
    page_count_uncertain = models.BooleanField(default=False)

    editing = models.TextField()
    no_editing = models.BooleanField(default=False, db_index=True)
    notes = models.TextField()

    keywords = TaggableManager()

    # Series and publisher links
    series = models.ForeignKey('Series', on_delete=models.CASCADE)
    indicia_publisher = models.ForeignKey(IndiciaPublisher,
                                          on_delete=models.CASCADE,
                                          null=True)
    indicia_pub_not_printed = models.BooleanField(default=False)
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE, null=True)
    no_brand = models.BooleanField(default=False, db_index=True)
    indicia_printer = models.ManyToManyField(IndiciaPrinter)
    no_indicia_printer = models.BooleanField(default=False)
    image_resources = GenericRelation(Image)

    awards = GenericRelation(ReceivedAward)

    # In production, this is a tinyint(1) because the set of numbers
    # is very small.  But syncdb produces an int(11).
    is_indexed = models.IntegerField(default=0, db_index=True)

    @property
    def indicia_image(self):
        img = Image.objects.filter(
            object_id=self.id,
            deleted=False,
            content_type=ContentType.objects.get_for_model(self),
            type__id=1)
        if img:
            return img.get()
        else:
            return None

    @property
    def soo_image(self):
        img = Image.objects.filter(
            object_id=self.id,
            deleted=False,
            content_type=ContentType.objects.get_for_model(self),
            type__id=2)
        if img:
            return img.get()
        else:
            return None

    @property
    def active_credits(self):
        return self.credits.exclude(deleted=True)

    def active_stories(self):
        return self.story_set.exclude(deleted=True)

    def _active_variants(self):
        return self.variant_set.exclude(deleted=True)

    def active_variants(self):
        return self._active_variants()

    def active_awards(self):
        return self.awards.exclude(deleted=True)

    def active_printers(self):
        return self.indicia_printer.all()

    def active_code_numbers(self):
        return self.code_number.all()

    def shown_stories(self):
        """ returns cover sequence and story sequences """
        if self.variant_of:
            stories_from = self.variant_of
        else:
            stories_from = self
        stories = list(stories_from.active_stories().order_by(
            'sequence_number').select_related(
                'type', 'migration_status').prefetch_related('feature_object'))
        if self.series.is_comics_publication:
            if (len(stories) > 0) and stories[0].type.id == 6:
                cover_story = stories.pop(0)
                if self.variant_of:
                    # can have only one sequence, the variant cover
                    if self.active_stories().count():
                        cover_story = self.active_stories()[0]
            elif self.variant_of and len(list(self.active_stories())):
                cover_story = self.active_stories()[0]
            else:
                cover_story = None
        else:
            cover_story = None
        return cover_story, stories

    def _active_covers(self):
        if self.can_have_cover():
            return self.cover_set.exclude(deleted=True)
        else:
            return self.cover_set.none()

    def active_covers(self):
        return self._active_covers()

    def variant_covers(self):
        """ returns the images from the variant issues """
        from .cover import Cover
        if self.variant_of:
            variant_issues = list(self.variant_of.active_variants().exclude(
                id=self.id).values_list('id', flat=True))
        else:
            variant_issues = list(self.active_variants().values_list(
                'id', flat=True))
        variant_covers = Cover.objects.filter(issue__id__in=variant_issues)\
                                      .exclude(deleted=True)
        if self.variant_of:
            variant_covers |= self.variant_of.active_covers()
        return variant_covers

    def shown_covers(self):
        return self.active_covers(), self.variant_covers()

    def show_printer(self):
        first = True
        printers = ''
        for printer in self.active_printers():
            if first:
                first = False
            else:
                printers += '; '
            printers += '<a href="%s">%s</a>' % (printer.get_absolute_url(),
                                                 esc(printer.name))
        return mark_safe(printers)

    def has_keywords(self):
        if self.series.is_singleton:
            return self.keywords.exists() or self.series.has_keywords()
        return self.keywords.exists()

    def has_content(self):
        """
        Simplifies UI checks for conditionals.  Content fields
        """
        return self.notes or \
            self.variant_of or \
            self.other_variants() or \
            self.has_keywords() or \
            self.has_reprints() or \
            self.active_awards().count()

    def has_covers(self):
        return self.can_have_cover() and self.active_covers().exists()

    def can_have_cover(self):
        if self.series.is_comics_publication:
            return True
        if self.is_indexed in [INDEXED['full'], INDEXED['ten_percent']]:
            return True
        else:
            return False

    def other_variants(self):
        if self.variant_of:
            variants = self.variant_of.active_variants().exclude(id=self.id)
        else:
            variants = self.active_variants()
        return list(variants)

    def _get_prev_next_issue(self):
        """
        Find the issues immediately before and after the given issue.
        """

        prev_issue = None
        next_issue = None

        earlier_issues = self.series.active_base_issues()\
                             .filter(sort_code__lt=self.sort_code)
        earlier_issues = earlier_issues.order_by('-sort_code')
        if earlier_issues:
            prev_issue = earlier_issues[0]

        later_issues = self.series.active_base_issues()\
                           .filter(sort_code__gt=self.sort_code)
        later_issues = later_issues.order_by('sort_code')
        if later_issues:
            next_issue = later_issues[0]

        return [prev_issue, next_issue]

    def get_prev_next_issue(self):
        return self._get_prev_next_issue()

    def has_reprints(self, ignore=STORY_TYPES['preview']):
        """Simplifies UI checks for conditionals, notes and reprint fields"""
        return self.from_reprints.count() or \
            self.to_reprints.exclude(target__type__id=ignore).count() or \
            self.from_issue_reprints.count() or \
            self.to_issue_reprints.count()

    def has_variants(self):
        return self.active_variants().exists()

    def has_dependents(self):
        # what about award_revisions ?
        has_non_story_deps = (
            self.has_variants() or self.has_reprints(ignore=None)
            or self.cover_revisions.active_set().exists()
            or self.variant_revisions.active_set().exists()
            or self.origin_reprint_revisions.active_set().exists()
            or self.target_reprint_revisions.active_set().exists())
        if has_non_story_deps:
            return True

        for story in self.active_stories():
            has_story_deps = (
                story.has_reprints(notes=False)
                or story.origin_reprint_revisions.active_set().exists()
                or story.target_reprint_revisions.active_set().exists())
            if has_story_deps:
                return True

        return False

    def can_upload_variants(self):
        if self.has_covers():
            currently_deleting = self.revisions.active_set() \
                                               .filter(deleted=True).exists()
            return not currently_deleting
        else:
            return False

    def set_indexed_status(self):
        """
        Sets the index status and returns the resulting stat change value.

        The return value of this method is intended for use in adjusting
        the "issue indexes" stat count.  GCD model modules cannot import
        CountStats and set them directly due to circular dependencies.
        """
        was_indexed = self.is_indexed

        if not self.variant_of:
            is_indexed = INDEXED['skeleton']
            if Decimal(self.page_count or 0) > 0:
                total_count = self.active_stories()\
                              .aggregate(Sum('page_count'))['page_count__sum']
                if total_count is None:
                    total_count = 0
                if (total_count > 0
                        and total_count >= Decimal('0.4') * self.page_count):
                    is_indexed = INDEXED['full']
                elif (total_count > 0
                      and total_count >= Decimal('0.1') * self.page_count):
                    is_indexed = INDEXED['ten_percent']

            if (is_indexed not in [INDEXED['full'], INDEXED['ten_percent']] and
                    self.active_stories().filter(type=StoryType.objects.get(
                        name='comic story')).exists()):
                is_indexed = INDEXED['partial']

            if is_indexed == INDEXED['full']:
                if self.page_count_uncertain or self.active_stories()\
                       .filter(page_count_uncertain=True).exists():
                    is_indexed = INDEXED['partial']

            if self.is_indexed != is_indexed:
                self.is_indexed = is_indexed
                self.save()
                if self.active_variants():
                    for variant in self.active_variants():
                        variant.is_indexed = is_indexed
                        variant.save()

        index_delta = 0
        if self.series.is_comics_publication:
            if not was_indexed and self.is_indexed:
                index_delta = 1
            elif was_indexed and not self.is_indexed:
                index_delta = -1
        return index_delta

    _update_stats = True

    def stat_counts(self):
        """
        Returns all count values relevant to this issue.

        Includes counts for the issue itself.

        Non-comics publications return statistics only for stories and covers,
        as non-comics issues do not count towards stats.

        Note that we have a special value "series issues", because non-variant
        issues are counted differently with respect to series than in general.
        A series always counts its own non-variant issues, even when the series
        is not a comics publication.
        """
        if self.deleted:
            return {}

        counts = {
            'stories': self.active_stories().count(),
            'covers': self.active_covers().count(),
        }

        if not self.variant_of_id:
            counts['series issues'] = 1

        if self.series.is_comics_publication:
            if self.variant_of_id:
                counts['variant issues'] = 1
            else:
                counts['issues'] = 1
                if self.is_indexed != INDEXED['skeleton']:
                    counts['issue indexes'] = 1
        return counts

    def get_absolute_url(self):
        return urlresolvers.reverse('show_issue', kwargs={'issue_id': self.id})

    @property
    def full_descriptor(self):
        if self.variant_name:
            return "%s [%s]" % (self.issue_descriptor, self.variant_name)
        if self.active_code_numbers().filter(number_type__id=1):
            return "%s (%s)" % (self.issue_descriptor,
                                self.active_code_numbers().get(
                                    number_type__id=1).number)
        return self.issue_descriptor

    @property
    def issue_descriptor(self):
        return issue_descriptor(self)

    @property
    def display_full_descriptor(self):
        number = self.full_descriptor
        if number:
            return '#' + number
        else:
            return ''

    @property
    def display_number(self):
        number = self.issue_descriptor
        if number:
            return '#' + number
        else:
            return ''

    def full_name(self, variant_name=True):
        if variant_name and self.variant_name:
            return '%s %s [%s]' % (self.series.full_name(),
                                   self.display_number, self.variant_name)
        if self.active_code_numbers().filter(number_type__id=1):
            return "%s %s (%s)" % (
                self.series.full_name(), self.display_number,
                self.active_code_numbers().get(number_type__id=1).number)
        return '%s %s' % (self.series.full_name(), self.display_number)

    def full_name_with_link(self, publisher=False):
        name_link = self.series.full_name_with_link(publisher)
        return mark_safe(
            '%s <a href="%s">%s</a>' %
            (name_link, self.get_absolute_url(), esc(self.display_number)))

    def show_series_and_issue_link(self):
        if self.display_number:
            issue_number = '%s' % (esc(self.display_number))
        else:
            issue_number = ''
        if self.variant_name:
            issue_number = '%s [%s]' % (issue_number, esc(self.variant_name))
        if issue_number:
            issue_number = '<a href="%s">%s</a>' % (self.get_absolute_url(),
                                                    issue_number)
        return mark_safe(
            '<a href="%s">%s</a> (%s series) %s' %
            (self.series.get_absolute_url(), esc(
                self.series.name), esc(self.series.year_began), issue_number))

    def short_name(self):
        if self.variant_name:
            return '%s %s [%s]' % (self.series.name, self.display_number,
                                   self.variant_name)
        else:
            return '%s %s' % (self.series.name, self.display_number)

    def __str__(self):
        if self.variant_name:
            return '%s %s [%s]' % (self.series, self.display_number,
                                   self.variant_name)
        else:
            return '%s %s' % (self.series, self.display_number)
示例#29
0
文件: registry.py 项目: gzqichang/wa
def setup_generic_relations(model_actor, relation_methods):
    """
    注册过的 actor_model_class 实例可以如此操作:
        actor.METHOD(target) # 建立 target 的特定 RELATION
        actor.dont_METHOD(target) # 或 no_METHOD 取消 target 的特定 RELATION
        #
        actor.actor_relations.filter(...)
        actor.METHOD_relations(...) # AS actor 的特定 RELATION filter
        actor.has_METHOD(target) # 与 target 是否存在特定 RELATION
    target_model_instance 可以有如下操作:
        target.target_relations.filter(...)
        target.METHOD_related(...) # AS target 的特定 RELATION filter
        target.was_METHOD(actor) # 与 actor 是否存在特定 RELATION
    owner_model_instance 可以有如下操作:
        owner.owner_relations.filter(...)
        owner.METHOD_related(...) # AS owner 的特定 RELATION filter
    """
    from qrelation import models
    #
    rel = GenericRelation(models.Relation,
        content_type_field='actor_type',
        object_id_field='actor_id',
        related_query_name='relations_with_%s_as_%s' % (label(model_actor), 'actor'))
    rel.contribute_to_class(model_actor, 'actor_relations')
    #
    actor_type = get_contenttype(model_actor)
    for method, kwargs in relation_methods.items():
        # 'follow': {
        #     'relation': models.REL_USER_FOLLOW,
        #     'target': 'quser.User',
        # }
        model_target = validate(kwargs.pop('target'))
        if not hasattr(model_target, 'target_relations'):
            rel = GenericRelation(models.Relation,
                content_type_field='target_type',
                object_id_field='target_id',
                related_query_name='relations_with_%s_as_%s' % (label(model_target), 'target'))
            rel.contribute_to_class(model_target, 'target_relations')
        model_owner = kwargs.pop('owner', None)
        if model_owner:
            model_owner = validate(model_owner)
            owner_type = get_contenttype(model_owner)
        if model_owner and not hasattr(model_owner, 'owner_relations'):
            rel = GenericRelation(models.Relation,
                content_type_field='owner_type',
                object_id_field='owner_id',
                related_query_name='relations_with_%s_as_%s' % (label(model_owner), 'owner'))
            rel.contribute_to_class(model_owner, 'owner_relations')
        #
        target_type = get_contenttype(model_target)
        relation, owner_field = kwargs.pop('relation'), kwargs.pop('owner_field', None)
        # 建立 relation
        setattr(model_actor, method, functools.partialmethod(
            relate, relation=relation, target_type=target_type, model_target=model_target, actor_type=actor_type, owner_field=owner_field))
        cancel_method = functools.partialmethod(
            relate, relation=relation, target_type=target_type, model_target=model_target, actor_type=actor_type, deleted=True)
        # 取消 relation
        setattr(model_actor, 'dont_%s' % method, cancel_method)
        setattr(model_actor, 'no_%s' % method, cancel_method)
        # 给 actor_model 增加类方法 METHOD_relations
        setattr(model_actor, '%s_relations' % method, functools.partialmethod(
            filter_relations, relation=relation))
        # 给 actor_model 增加类方法 has_METHOD
        setattr(model_actor, 'has_%s' % method, functools.partialmethod(
            check_relation, relation=relation, target_type=target_type, model_target=model_target))
        # 给 target_model 增加类方法 METHOD_related
        setattr(model_target, '%s_related' % method, functools.partialmethod(
            filter_related, relation=relation))
        # 给 target_model 增加类方法 was_METHOD
        setattr(model_target, 'was_%s' % method, functools.partialmethod(
            check_related, relation=relation, actor_type=actor_type, model_actor=model_actor))
        if not model_owner:
            continue
        # 给 owner_model 增加类方法 
        setattr(model_owner, '%s_related' % method, functools.partialmethod(
            filter_owner, relation=relation))
示例#30
0
class GenRelReference(models.Model):
    references = GenericRelation(ReferencedByGenRel)
示例#31
0
文件: models.py 项目: morad7/tendenci
class BasePage(TendenciBaseModel):
    guid = models.CharField(max_length=40)
    title = models.CharField(max_length=500, blank=True)
    slug = SlugField(_('URL Path'))
    header_image = models.ForeignKey('HeaderImage', null=True)
    content = tinymce_models.HTMLField()
    view_contact_form = models.BooleanField(default=False)
    design_notes = models.TextField(_('Design Notes'), blank=True)
    syndicate = models.BooleanField(_('Include in RSS feed'), default=False)
    template = models.CharField(_('Template'), max_length=50, blank=True)
    tags = TagField(blank=True)
    meta = models.OneToOneField(MetaTags, null=True)
    categories = GenericRelation(CategoryItem,
                                 object_id_field="object_id",
                                 content_type_field="content_type")

    class Meta:
        abstract = True
        app_label = 'pages'

    def save(self, *args, **kwargs):
        if not self.guid:
            self.guid = str(uuid.uuid1())
        super(BasePage, self).save(*args, **kwargs)
        if self.header_image:
            if self.is_public():
                set_s3_file_permission(self.header_image.file, public=True)
            else:
                set_s3_file_permission(self.header_image.file, public=False)

    def __unicode__(self):
        return self.title

    def get_header_image_url(self):
        if not self.header_image:
            return ''

        if self.is_public():
            return self.header_image.file.url

        return reverse('page.header_image', args=[self.id])

    def is_public(self):
        return all([
            self.allow_anonymous_view, self.status, self.status_detail
            in ['active']
        ])

    @property
    def category_set(self):
        items = {}
        for cat in self.categories.select_related('category__name',
                                                  'parent__name'):
            if cat.category:
                items["category"] = cat.category
            elif cat.parent:
                items["sub_category"] = cat.parent
        return items

    @property
    def version(self):
        if self.status and self.status_detail:
            return self.status_detail + '-' + str(self.pk) + ' ' + str(
                self.create_dt)
        elif not self.status:
            return 'deleted-' + str(self.pk) + ' ' + str(self.create_dt)
        return ''
示例#32
0
class Event(models.Model):
    '''
    Container model for general metadata and associated ``Occurrence`` entries.
    '''
    title = models.CharField(_('title'), max_length=32)
    location = models.ForeignKey(BookingLocation,
                                 on_delete=models.CASCADE,
                                 limit_choices_to={'active': True})

    description = models.CharField(_('description'),
                                   max_length=100,
                                   blank=True)
    notes = GenericRelation(Note, verbose_name=_('notes'))

    #===========================================================================
    class Meta:
        verbose_name = _('event')
        verbose_name_plural = _('events')
        ordering = ('title', )

    #---------------------------------------------------------------------------
    def __str__(self):
        return self.title

    #---------------------------------------------------------------------------
    def get_absolute_url(self):
        return reverse('swingtime-event',
                       args=[self.location.slug,
                             str(self.id)])

    #---------------------------------------------------------------------------
    def add_occurrences(self, start_time, end_time, **rrule_params):
        '''
        Add one or more occurences to the event using a comparable API to
        ``dateutil.rrule``.

        If ``rrule_params`` does not contain a ``freq``, one will be defaulted
        to ``rrule.DAILY``.

        Because ``rrule.rrule`` returns an iterator that can essentially be
        unbounded, we need to slightly alter the expected behavior here in order
        to enforce a finite number of occurrence creation.

        If both ``count`` and ``until`` entries are missing from ``rrule_params``,
        only a single ``Occurrence`` instance will be created using the exact
        ``start_time`` and ``end_time`` values.
        '''
        rrule_params.setdefault('freq', rrule.DAILY)

        if 'count' not in rrule_params and 'until' not in rrule_params:
            self.occurrence_set.create(start_time=start_time,
                                       end_time=end_time)
        else:
            # weird things can happen with timezones here if we hit
            #   a daylight savings time transition...
            #   So make everything naive and then convert back to aware.
            start_time = force_naive(start_time)
            end_time = force_naive(end_time)
            if 'until' in rrule_params:
                rrule_params['until'] = force_naive(rrule_params['until'])
            delta = end_time - start_time

            for ev in rrule.rrule(dtstart=start_time, **rrule_params):
                ev_start = force_aware(ev)
                ev_end = force_aware(ev + delta)
                self.occurrence_set.create(start_time=ev_start,
                                           end_time=ev_end)

    #---------------------------------------------------------------------------
    def upcoming_occurrences(self):
        '''
        Return all occurrences that are set to start on or after the current
        time.
        '''
        return self.occurrence_set.filter(start_time__gte=datetime_now())

    #---------------------------------------------------------------------------
    def next_occurrence(self):
        '''
        Return the single occurrence set to start on or after the current time
        if available, otherwise ``None``.
        '''
        upcoming = self.upcoming_occurrences()
        return upcoming and upcoming[0] or None

    #---------------------------------------------------------------------------
    def daily_occurrences(self, dt=None):
        '''
        Convenience method wrapping ``Occurrence.objects.daily_occurrences``.
        '''
        return Occurrence.objects.daily_occurrences(dt=dt, event=self)
示例#33
0
class EmbalagemProduto(Nomeavel, TemChaveExterna):
    item = GenericRelation('ItemCadastro', related_query_name='embalagem_produto')

    def __str__(self):
        return self.nome
示例#34
0
class Fabricante(Nomeavel, TemChaveExterna):
    item = GenericRelation('ItemCadastro', related_query_name='fabricante')

    def __str__(self):
        return self.nome
示例#35
0
class ScriptMetaData(CoreMetaData):
    scriptspecificmetadata = GenericRelation(ScriptSpecificMetadata)

    @property
    def resource(self):
        return ScriptResource.objects.filter(object_id=self.id).first()

    @property
    def program(self):
        return self.scriptspecificmetadata.all().first()

    @property
    def script_specific_metadata(self):
        return self.program

    @property
    def serializer(self):
        """Return an instance of rest_framework Serializer for self """
        from serializers import ScriptMetaDataSerializer
        return ScriptMetaDataSerializer(self)

    @classmethod
    def parse_for_bulk_update(cls, metadata, parsed_metadata):
        """Overriding the base class method"""

        CoreMetaData.parse_for_bulk_update(metadata, parsed_metadata)
        keys_to_update = metadata.keys()
        if 'scriptspecificmetadata' in keys_to_update:
            parsed_metadata.append({
                "scriptspecificmetadata":
                metadata.pop('scriptspecificmetadata')
            })

    @classmethod
    def get_supported_element_names(cls):
        elements = super(ScriptMetaData, cls).get_supported_element_names()
        elements.append('ScriptSpecificMetadata')
        return elements

    def has_all_required_elements(self):
        if self.get_required_missing_elements():
            return False
        return True

    def get_required_missing_elements(self):  # show missing required meta
        missing_required_elements = super(
            ScriptMetaData, self).get_required_missing_elements()
        if not self.program:
            missing_required_elements.append('Script Language')
            missing_required_elements.append('Programming Language Version')
        else:
            if not self.program.scriptLanguage:
                missing_required_elements.append('Script Language')
            if not self.program.languageVersion:
                missing_required_elements.append(
                    'Programming Language Version')

        return missing_required_elements

    def update(self, metadata, user):
        # overriding the base class update method for bulk update of metadata
        from forms import ScriptFormValidation

        super(ScriptMetaData, self).update(metadata, user)
        attribute_mappings = {'scriptspecificmetadata': 'program'}
        with transaction.atomic():
            # update/create non-repeatable element
            for element_name in attribute_mappings.keys():
                for dict_item in metadata:
                    if element_name in dict_item:
                        validation_form = ScriptFormValidation(
                            dict_item[element_name])
                        if not validation_form.is_valid():
                            err_string = self.get_form_errors_as_string(
                                validation_form)
                            raise ValidationError(err_string)
                        element_property_name = attribute_mappings[
                            element_name]
                        self.update_non_repeatable_element(
                            element_name, metadata, element_property_name)
                        break

    def get_xml(self, pretty_print=True, include_format_elements=True):

        # get the xml string for R Script
        xml_string = super(ScriptMetaData,
                           self).get_xml(pretty_print=pretty_print)

        # create  etree element
        RDF_ROOT = etree.fromstring(xml_string)

        # get the root 'Description' element, which contains all other elements
        container = RDF_ROOT.find('rdf:Description',
                                  namespaces=self.NAMESPACES)

        if self.program:

            if self.program.scriptReleaseDate:
                script_release_date = etree.SubElement(
                    container,
                    '{%s}scriptReleaseDate' % self.NAMESPACES['hsterms'])
                script_release_date.text = self.program.scriptReleaseDate.isoformat(
                )

            script_language = etree.SubElement(
                container, '{%s}scriptLanguage' % self.NAMESPACES['hsterms'])
            script_language.text = self.program.scriptLanguage

            language_version = etree.SubElement(
                container, '{%s}languageVersion' % self.NAMESPACES['hsterms'])
            language_version.text = self.program.scriptVersion

            script_version = etree.SubElement(
                container, '{%s}scriptVersion' % self.NAMESPACES['hsterms'])
            script_version.text = self.program.scriptVersion

            script_dependencies = etree.SubElement(
                container,
                '{%s}scriptDependencies' % self.NAMESPACES['hsterms'])
            script_dependencies.text = self.program.scriptVersion

            script_code_repository = etree.SubElement(
                container,
                '{%s}scriptCodeRepository' % self.NAMESPACES['hsterms'])
            script_code_repository.text = self.program.scriptCodeRepository

        xml_string = etree.tostring(RDF_ROOT, pretty_print=pretty_print)

        return xml_string
class Place(dalmeUuid):
    std_name = models.CharField(max_length=255)
    type = models.IntegerField(db_index=True)
    attributes = GenericRelation('Attribute')
    instances = GenericRelation('Entity_phrase')
    tags = GenericRelation('Tag')
示例#37
0
class Marca(Nomeavel, TemChaveExterna):
    item = GenericRelation('ItemCadastro', related_query_name='marca')

    def __str__(self):
        return self.nome
示例#38
0
文件: models.py 项目: yuta2/netbox
class VRF(ChangeLoggedModel, CustomFieldModel):
    """
    A virtual routing and forwarding (VRF) table represents a discrete layer three forwarding domain (e.g. a routing
    table). Prefixes and IPAddresses can optionally be assigned to VRFs. (Prefixes and IPAddresses not assigned to a VRF
    are said to exist in the "global" table.)
    """
    name = models.CharField(
        max_length=50
    )
    rd = models.CharField(
        max_length=VRF_RD_MAX_LENGTH,
        unique=True,
        blank=True,
        null=True,
        verbose_name='Route distinguisher'
    )
    tenant = models.ForeignKey(
        to='tenancy.Tenant',
        on_delete=models.PROTECT,
        related_name='vrfs',
        blank=True,
        null=True
    )
    enforce_unique = models.BooleanField(
        default=True,
        verbose_name='Enforce unique space',
        help_text='Prevent duplicate prefixes/IP addresses within this VRF'
    )
    description = models.CharField(
        max_length=100,
        blank=True
    )
    custom_field_values = GenericRelation(
        to='extras.CustomFieldValue',
        content_type_field='obj_type',
        object_id_field='obj_id'
    )

    tags = TaggableManager(through=TaggedItem)

    csv_headers = ['name', 'rd', 'tenant', 'enforce_unique', 'description']
    clone_fields = [
        'tenant', 'enforce_unique', 'description',
    ]

    class Meta:
        ordering = ('name', 'rd', 'pk')  # (name, rd) may be non-unique
        verbose_name = 'VRF'
        verbose_name_plural = 'VRFs'

    def __str__(self):
        return self.display_name or super().__str__()

    def get_absolute_url(self):
        return reverse('ipam:vrf', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.rd,
            self.tenant.name if self.tenant else None,
            self.enforce_unique,
            self.description,
        )

    @property
    def display_name(self):
        if self.rd:
            return "{} ({})".format(self.name, self.rd)
        return self.name
示例#39
0
文件: models.py 项目: yuta2/netbox
class IPAddress(ChangeLoggedModel, CustomFieldModel):
    """
    An IPAddress represents an individual IPv4 or IPv6 address and its mask. The mask length should match what is
    configured in the real world. (Typically, only loopback interfaces are configured with /32 or /128 masks.) Like
    Prefixes, IPAddresses can optionally be assigned to a VRF. An IPAddress can optionally be assigned to an Interface.
    Interfaces can have zero or more IPAddresses assigned to them.

    An IPAddress can also optionally point to a NAT inside IP, designating itself as a NAT outside IP. This is useful,
    for example, when mapping public addresses to private addresses. When an Interface has been assigned an IPAddress
    which has a NAT outside IP, that Interface's Device can use either the inside or outside IP as its primary IP.
    """
    family = models.PositiveSmallIntegerField(
        choices=IPAddressFamilyChoices,
        editable=False
    )
    address = IPAddressField(
        help_text='IPv4 or IPv6 address (with mask)'
    )
    vrf = models.ForeignKey(
        to='ipam.VRF',
        on_delete=models.PROTECT,
        related_name='ip_addresses',
        blank=True,
        null=True,
        verbose_name='VRF'
    )
    tenant = models.ForeignKey(
        to='tenancy.Tenant',
        on_delete=models.PROTECT,
        related_name='ip_addresses',
        blank=True,
        null=True
    )
    status = models.CharField(
        max_length=50,
        choices=IPAddressStatusChoices,
        default=IPAddressStatusChoices.STATUS_ACTIVE,
        help_text='The operational status of this IP'
    )
    role = models.CharField(
        max_length=50,
        choices=IPAddressRoleChoices,
        blank=True,
        help_text='The functional role of this IP'
    )
    interface = models.ForeignKey(
        to='dcim.Interface',
        on_delete=models.CASCADE,
        related_name='ip_addresses',
        blank=True,
        null=True
    )
    nat_inside = models.OneToOneField(
        to='self',
        on_delete=models.SET_NULL,
        related_name='nat_outside',
        blank=True,
        null=True,
        verbose_name='NAT (Inside)',
        help_text='The IP for which this address is the "outside" IP'
    )
    dns_name = models.CharField(
        max_length=255,
        blank=True,
        validators=[DNSValidator],
        verbose_name='DNS Name',
        help_text='Hostname or FQDN (not case-sensitive)'
    )
    description = models.CharField(
        max_length=100,
        blank=True
    )
    custom_field_values = GenericRelation(
        to='extras.CustomFieldValue',
        content_type_field='obj_type',
        object_id_field='obj_id'
    )

    objects = IPAddressManager()
    tags = TaggableManager(through=TaggedItem)

    csv_headers = [
        'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface_name', 'is_primary',
        'dns_name', 'description',
    ]
    clone_fields = [
        'vrf', 'tenant', 'status', 'role', 'description',
    ]

    STATUS_CLASS_MAP = {
        'active': 'primary',
        'reserved': 'info',
        'deprecated': 'danger',
        'dhcp': 'success',
    }

    ROLE_CLASS_MAP = {
        'loopback': 'default',
        'secondary': 'primary',
        'anycast': 'warning',
        'vip': 'success',
        'vrrp': 'success',
        'hsrp': 'success',
        'glbp': 'success',
        'carp': 'success',
    }

    class Meta:
        ordering = ('family', 'address', 'pk')  # (family, address) may be non-unique
        verbose_name = 'IP address'
        verbose_name_plural = 'IP addresses'

    def __str__(self):
        return str(self.address)

    def get_absolute_url(self):
        return reverse('ipam:ipaddress', args=[self.pk])

    def get_duplicates(self):
        return IPAddress.objects.filter(vrf=self.vrf, address__net_host=str(self.address.ip)).exclude(pk=self.pk)

    def clean(self):

        if self.address:

            # /0 masks are not acceptable
            if self.address.prefixlen == 0:
                raise ValidationError({
                    'address': "Cannot create IP address with /0 mask."
                })

            # Enforce unique IP space (if applicable)
            if self.role not in IPADDRESS_ROLES_NONUNIQUE and ((
                self.vrf is None and settings.ENFORCE_GLOBAL_UNIQUE
            ) or (
                self.vrf and self.vrf.enforce_unique
            )):
                duplicate_ips = self.get_duplicates()
                if duplicate_ips:
                    raise ValidationError({
                        'address': "Duplicate IP address found in {}: {}".format(
                            "VRF {}".format(self.vrf) if self.vrf else "global table",
                            duplicate_ips.first(),
                        )
                    })

        if self.pk:

            # Check for primary IP assignment that doesn't match the assigned device/VM
            device = Device.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first()
            if device:
                if self.interface is None:
                    raise ValidationError({
                        'interface': "IP address is primary for device {} but not assigned".format(device)
                    })
                elif (device.primary_ip4 == self or device.primary_ip6 == self) and self.interface.device != device:
                    raise ValidationError({
                        'interface': "IP address is primary for device {} but assigned to {} ({})".format(
                            device, self.interface.device, self.interface
                        )
                    })
            vm = VirtualMachine.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first()
            if vm:
                if self.interface is None:
                    raise ValidationError({
                        'interface': "IP address is primary for virtual machine {} but not assigned".format(vm)
                    })
                elif (vm.primary_ip4 == self or vm.primary_ip6 == self) and self.interface.virtual_machine != vm:
                    raise ValidationError({
                        'interface': "IP address is primary for virtual machine {} but assigned to {} ({})".format(
                            vm, self.interface.virtual_machine, self.interface
                        )
                    })

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

        # Record address family
        if isinstance(self.address, netaddr.IPNetwork):
            self.family = self.address.version

        # Force dns_name to lowercase
        self.dns_name = self.dns_name.lower()

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

    def to_objectchange(self, action):
        # Annotate the assigned Interface (if any)
        try:
            parent_obj = self.interface
        except ObjectDoesNotExist:
            parent_obj = None

        return ObjectChange(
            changed_object=self,
            object_repr=str(self),
            action=action,
            related_object=parent_obj,
            object_data=serialize_object(self)
        )

    def to_csv(self):

        # Determine if this IP is primary for a Device
        if self.family == 4 and getattr(self, 'primary_ip4_for', False):
            is_primary = True
        elif self.family == 6 and getattr(self, 'primary_ip6_for', False):
            is_primary = True
        else:
            is_primary = False

        return (
            self.address,
            self.vrf.name if self.vrf else None,
            self.tenant.name if self.tenant else None,
            self.get_status_display(),
            self.get_role_display(),
            self.device.identifier if self.device else None,
            self.virtual_machine.name if self.virtual_machine else None,
            self.interface.name if self.interface else None,
            is_primary,
            self.dns_name,
            self.description,
        )

    def _set_mask_length(self, value):
        """
        Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
        e.g. for bulk editing.
        """
        if self.address is not None:
            self.address.prefixlen = value
    mask_length = property(fset=_set_mask_length)

    @property
    def device(self):
        if self.interface:
            return self.interface.device
        return None

    @property
    def virtual_machine(self):
        if self.interface:
            return self.interface.virtual_machine
        return None

    def get_status_class(self):
        return self.STATUS_CLASS_MAP.get(self.status)

    def get_role_class(self):
        return self.ROLE_CLASS_MAP[self.role]
示例#40
0
文件: models.py 项目: yuta2/netbox
class Prefix(ChangeLoggedModel, CustomFieldModel):
    """
    A Prefix represents an IPv4 or IPv6 network, including mask length. Prefixes can optionally be assigned to Sites and
    VRFs. A Prefix must be assigned a status and may optionally be assigned a used-define Role. A Prefix can also be
    assigned to a VLAN where appropriate.
    """
    family = models.PositiveSmallIntegerField(
        choices=IPAddressFamilyChoices,
        editable=False
    )
    prefix = IPNetworkField(
        help_text='IPv4 or IPv6 network with mask'
    )
    site = models.ForeignKey(
        to='dcim.Site',
        on_delete=models.PROTECT,
        related_name='prefixes',
        blank=True,
        null=True
    )
    vrf = models.ForeignKey(
        to='ipam.VRF',
        on_delete=models.PROTECT,
        related_name='prefixes',
        blank=True,
        null=True,
        verbose_name='VRF'
    )
    tenant = models.ForeignKey(
        to='tenancy.Tenant',
        on_delete=models.PROTECT,
        related_name='prefixes',
        blank=True,
        null=True
    )
    vlan = models.ForeignKey(
        to='ipam.VLAN',
        on_delete=models.PROTECT,
        related_name='prefixes',
        blank=True,
        null=True,
        verbose_name='VLAN'
    )
    status = models.CharField(
        max_length=50,
        choices=PrefixStatusChoices,
        default=PrefixStatusChoices.STATUS_ACTIVE,
        verbose_name='Status',
        help_text='Operational status of this prefix'
    )
    role = models.ForeignKey(
        to='ipam.Role',
        on_delete=models.SET_NULL,
        related_name='prefixes',
        blank=True,
        null=True,
        help_text='The primary function of this prefix'
    )
    is_pool = models.BooleanField(
        verbose_name='Is a pool',
        default=False,
        help_text='All IP addresses within this prefix are considered usable'
    )
    description = models.CharField(
        max_length=100,
        blank=True
    )
    custom_field_values = GenericRelation(
        to='extras.CustomFieldValue',
        content_type_field='obj_type',
        object_id_field='obj_id'
    )

    objects = PrefixQuerySet.as_manager()
    tags = TaggableManager(through=TaggedItem)

    csv_headers = [
        'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description',
    ]
    clone_fields = [
        'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'description',
    ]

    STATUS_CLASS_MAP = {
        'container': 'default',
        'active': 'primary',
        'reserved': 'info',
        'deprecated': 'danger',
    }

    class Meta:
        ordering = (F('vrf').asc(nulls_first=True), 'family', 'prefix', 'pk')  # (vrf, family, prefix) may be non-unique
        verbose_name_plural = 'prefixes'

    def __str__(self):
        return str(self.prefix)

    def get_absolute_url(self):
        return reverse('ipam:prefix', args=[self.pk])

    def clean(self):

        if self.prefix:

            # /0 masks are not acceptable
            if self.prefix.prefixlen == 0:
                raise ValidationError({
                    'prefix': "Cannot create prefix with /0 mask."
                })

            # Disallow host masks
            if self.prefix.version == 4 and self.prefix.prefixlen == 32:
                raise ValidationError({
                    'prefix': "Cannot create host addresses (/32) as prefixes. Create an IPv4 address instead."
                })
            elif self.prefix.version == 6 and self.prefix.prefixlen == 128:
                raise ValidationError({
                    'prefix': "Cannot create host addresses (/128) as prefixes. Create an IPv6 address instead."
                })

            # Enforce unique IP space (if applicable)
            if (self.vrf is None and settings.ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
                duplicate_prefixes = self.get_duplicates()
                if duplicate_prefixes:
                    raise ValidationError({
                        'prefix': "Duplicate prefix found in {}: {}".format(
                            "VRF {}".format(self.vrf) if self.vrf else "global table",
                            duplicate_prefixes.first(),
                        )
                    })

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

        if isinstance(self.prefix, netaddr.IPNetwork):

            # Clear host bits from prefix
            self.prefix = self.prefix.cidr

            # Record address family
            self.family = self.prefix.version

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

    def to_csv(self):
        return (
            self.prefix,
            self.vrf.name if self.vrf else None,
            self.tenant.name if self.tenant else None,
            self.site.name if self.site else None,
            self.vlan.group.name if self.vlan and self.vlan.group else None,
            self.vlan.vid if self.vlan else None,
            self.get_status_display(),
            self.role.name if self.role else None,
            self.is_pool,
            self.description,
        )

    def _set_prefix_length(self, value):
        """
        Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
        e.g. for bulk editing.
        """
        if self.prefix is not None:
            self.prefix.prefixlen = value
    prefix_length = property(fset=_set_prefix_length)

    def get_status_class(self):
        return self.STATUS_CLASS_MAP.get(self.status)

    def get_duplicates(self):
        return Prefix.objects.filter(vrf=self.vrf, prefix=str(self.prefix)).exclude(pk=self.pk)

    def get_child_prefixes(self):
        """
        Return all Prefixes within this Prefix and VRF. If this Prefix is a container in the global table, return child
        Prefixes belonging to any VRF.
        """
        if self.vrf is None and self.status == PrefixStatusChoices.STATUS_CONTAINER:
            return Prefix.objects.filter(prefix__net_contained=str(self.prefix))
        else:
            return Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)

    def get_child_ips(self):
        """
        Return all IPAddresses within this Prefix and VRF. If this Prefix is a container in the global table, return
        child IPAddresses belonging to any VRF.
        """
        if self.vrf is None and self.status == PrefixStatusChoices.STATUS_CONTAINER:
            return IPAddress.objects.filter(address__net_host_contained=str(self.prefix))
        else:
            return IPAddress.objects.filter(address__net_host_contained=str(self.prefix), vrf=self.vrf)

    def get_available_prefixes(self):
        """
        Return all available Prefixes within this prefix as an IPSet.
        """
        prefix = netaddr.IPSet(self.prefix)
        child_prefixes = netaddr.IPSet([child.prefix for child in self.get_child_prefixes()])
        available_prefixes = prefix - child_prefixes

        return available_prefixes

    def get_available_ips(self):
        """
        Return all available IPs within this prefix as an IPSet.
        """
        prefix = netaddr.IPSet(self.prefix)
        child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()])
        available_ips = prefix - child_ips

        # All IP addresses within a pool are considered usable
        if self.is_pool:
            return available_ips

        # All IP addresses within a point-to-point prefix (IPv4 /31 or IPv6 /127) are considered usable
        if (
            self.family == 4 and self.prefix.prefixlen == 31  # RFC 3021
        ) or (
            self.family == 6 and self.prefix.prefixlen == 127  # RFC 6164
        ):
            return available_ips

        # Omit first and last IP address from the available set
        available_ips -= netaddr.IPSet([
            netaddr.IPAddress(self.prefix.first),
            netaddr.IPAddress(self.prefix.last),
        ])

        return available_ips

    def get_first_available_prefix(self):
        """
        Return the first available child prefix within the prefix (or None).
        """
        available_prefixes = self.get_available_prefixes()
        if not available_prefixes:
            return None
        return available_prefixes.iter_cidrs()[0]

    def get_first_available_ip(self):
        """
        Return the first available IP within the prefix (or None).
        """
        available_ips = self.get_available_ips()
        if not available_ips:
            return None
        return '{}/{}'.format(next(available_ips.__iter__()), self.prefix.prefixlen)

    def get_utilization(self):
        """
        Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of
        "container", calculate utilization based on child prefixes. For all others, count child IP addresses.
        """
        if self.status == PrefixStatusChoices.STATUS_CONTAINER:
            queryset = Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)
            child_prefixes = netaddr.IPSet([p.prefix for p in queryset])
            return int(float(child_prefixes.size) / self.prefix.size * 100)
        else:
            # Compile an IPSet to avoid counting duplicate IPs
            child_count = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]).size
            prefix_size = self.prefix.size
            if self.family == 4 and self.prefix.prefixlen < 31 and not self.is_pool:
                prefix_size -= 2
            return int(float(child_count) / prefix_size * 100)
示例#41
0
class FriendList(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL,
                                on_delete=models.CASCADE,
                                related_name="user")
    friends = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                     blank=True,
                                     related_name="friends")

    notifications = GenericRelation(Notification)

    def __str__(self):
        return self.user.username

    def add_friend(self, account):
        # Adding a friend into friend list
        if not account in self.friends.all():
            self.friends.add(account)
            self.save()

            content_type = ContentType.objects.get_for_model(self)

            self.notifications.create(
                target=self.user,
                from_user=account,
                redirect_url=f"{settings.BASE_URL}/account/{account.pk}/",
                statement=f"You are now friend with {account.user}",
                content_type=content_type)
            self.save()

            # Creating a private chat room when two users become friends
            chat = find_or_create_private_chat(self.user, account)
            if not chat.is_active:
                chat.is_active = True
                chat.save()

    def remove_friend(self, account):
        # Removing a friend from the friend list
        if account in self.friends.all():
            self.friends.remove(account)

            # Deactivating the private chat room when two users are no longer friends
            chat = find_or_create_private_chat(self.user, account)
            if chat.is_active:
                chat.is_active = False
                chat.save()

    def unfriend(self, removee):
        # Removing a friend
        remover_friends_list = self
        remover_friends_list.remove_friend(removee)

        friends_list = FriendList.objects.get(user=removee)
        friends_list.remove_friend(self.user)

        content_type = ContentType.objects.get_for_model(self)

        # Notification for removee
        friends_list.notifications.create(
            target=removee,
            from_user=self.user,
            redirect_url=f"{settings.BASE_URL}/account/{self.user.pk}/",
            statement=f"You are no longer friends with {self.user.username}.",
            content_type=content_type,
        )

        # Notification for remover
        self.notifications.create(
            target=self.user,
            from_user=removee,
            redirect_url=f"{settings.BASE_URL}/account/{removee.pk}/",
            statement=f"You are no longer friends with {removee.username}.",
            content_type=content_type,
        )

    @property
    def get_cname(self):
        """
        For determining what kind of object is associated with a Notification
        """
        return "FriendList"

    def is_mutual_friends(self, friend):
        # Getting the result if the friends are mutual
        if friend in self.friends.all():
            return True
        return False