Ejemplo n.º 1
1
 def ready(self):
     # Connections may already exist before we are called.
     for conn in connections.all():
         if conn.connection is not None:
             register_type_handlers(conn)
     connection_created.connect(register_type_handlers)
     CharField.register_lookup(Unaccent)
     TextField.register_lookup(Unaccent)
     CharField.register_lookup(SearchLookup)
     TextField.register_lookup(SearchLookup)
     CharField.register_lookup(TrigramSimilar)
     TextField.register_lookup(TrigramSimilar)
Ejemplo n.º 2
0
    def __init__(self, *args, **kwargs):
        """
        Allow specifying a different format for the key used to identify
        versionized content in the model-definition.

        """
        #TODO: check if the string has the correct format
        self.rcskey_format = kwargs.pop('rcskey_format', "%s/%s/%s/%s.txt")
        self.IS_VERSIONED = True # so we can figure out that this field is versionized
        TextField.__init__(self, *args, **kwargs)
Ejemplo n.º 3
0
    def __init__(self, *args, **kwargs):
        """
        Allow specifying a different format for the key used to identify
        versionized content in the model-definition.

        """
        if kwargs.get("rcskey_format", False):
            self.rcskey_format = kwargs["rcskey_format"]
            del kwargs["rcskey_format"]
            # TODO: check if the string has the correct format
        else:
            self.rcskey_format = "%s/%s/%s/%s.txt"
        self.IS_VERSIONED = True  # so we can figure out that this field is versionized
        TextField.__init__(self, *args, **kwargs)
Ejemplo n.º 4
0
 def ready(self):
     connection_created.connect(register_hstore_handler)
     CharField.register_lookup(Unaccent)
     TextField.register_lookup(Unaccent)
     CharField.register_lookup(SearchLookup)
     TextField.register_lookup(SearchLookup)
     CharField.register_lookup(TrigramSimilar)
     TextField.register_lookup(TrigramSimilar)
Ejemplo n.º 5
0
    def add_lookups(self):
        from django.db.models import CharField, TextField
        from django_mysql.models.lookups import (
            CaseSensitiveExact, Soundex, SoundsLike
        )

        CharField.register_lookup(CaseSensitiveExact)
        CharField.register_lookup(SoundsLike)
        CharField.register_lookup(Soundex)
        TextField.register_lookup(CaseSensitiveExact)
        TextField.register_lookup(SoundsLike)
        TextField.register_lookup(Soundex)
Ejemplo n.º 6
0
def uninstall_if_needed(setting, value, enter, **kwargs):
    """
    Undo the effects of PostgresConfig.ready() when django.contrib.postgres
    is "uninstalled" by override_settings().
    """
    if not enter and setting == 'INSTALLED_APPS' and 'django.contrib.postgres' not in set(value):
        connection_created.disconnect(register_type_handlers)
        CharField._unregister_lookup(Unaccent)
        TextField._unregister_lookup(Unaccent)
        CharField._unregister_lookup(SearchLookup)
        TextField._unregister_lookup(SearchLookup)
        CharField._unregister_lookup(TrigramSimilar)
        TextField._unregister_lookup(TrigramSimilar)
        # Disconnect this receiver until the next time this app is installed
        # and ready() connects it again to prevent unnecessary processing on
        # each setting change.
        setting_changed.disconnect(uninstall_if_needed)
Ejemplo n.º 7
0
 def ready(self):
     # Connections may already exist before we are called.
     for conn in connections.all():
         if conn.vendor == 'postgresql':
             conn.introspection.data_types_reverse.update({
                 3802: 'django.contrib.postgres.fields.JSONField',
                 3904: 'django.contrib.postgres.fields.IntegerRangeField',
                 3906: 'django.contrib.postgres.fields.DecimalRangeField',
                 3910: 'django.contrib.postgres.fields.DateTimeRangeField',
                 3912: 'django.contrib.postgres.fields.DateRangeField',
                 3926: 'django.contrib.postgres.fields.BigIntegerRangeField',
             })
             if conn.connection is not None:
                 register_type_handlers(conn)
     connection_created.connect(register_type_handlers)
     CharField.register_lookup(Unaccent)
     TextField.register_lookup(Unaccent)
     CharField.register_lookup(SearchLookup)
     TextField.register_lookup(SearchLookup)
     CharField.register_lookup(TrigramSimilar)
     TextField.register_lookup(TrigramSimilar)
Ejemplo n.º 8
0
 def ready(self):
     connection_created.connect(register_hstore_handler)
     CharField.register_lookup(Unaccent)
     TextField.register_lookup(Unaccent)
Ejemplo n.º 9
0
#************************************************

from django.db.models import Transform, Field

class UpperCase(Transform):
    lookup_name = 'upper'
    bilateral = True

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return "UPPER(%s)" % lhs, params

from django.db.models import CharField, TextField
CharField.register_lookup(UpperCase)
TextField.register_lookup(UpperCase)


class AbsoluteValue(Transform):
    lookup_name = 'abs'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return "ABS(%s)" % lhs, params

    @property
    def output_field(self):
        return FloatField()

#*****************************8
Ejemplo n.º 10
0
class Location(AbstractStreetAddress):
    location_id = CharField(max_length=255, blank=True, null=True)
    location_status = CharField(max_length=10,
                                choices=SQUARE_STATUS,
                                default=STATUS_ACTIVE)
    location_type = CharField(max_length=10,
                              choices=SQUARE_LOCATION_TYPE,
                              default="PHYSICAL")
    business_name = CharField(max_length=255, blank=True, null=True)
    description = TextField(blank=True, null=True)
    phone_number = CharField(max_length=32, blank=True, null=True)
    email = EmailField(blank=True, null=True)
    website_url = URLField(blank=True, null=True)
    facebook_url = URLField(blank=True, null=True)
    instagram_username = CharField(max_length=255, blank=True, null=True)
    twitter_username = CharField(max_length=255, blank=True, null=True)
    country = CharField(max_length=2, blank=True, null=True)
    created_at = DateTimeField(null=True)
    currency = CharField(max_length=10, blank=True, null=True)
    language_code = CharField(max_length=10, blank=True, null=True)
    mcc = CharField(max_length=10, blank=True, null=True)
    merchant_id = CharField(max_length=32, blank=True, null=True)

    def __str__(self):
        return self.business_name if self.business_name is not None else self.name

    @property
    def mcc_description(self):
        return iso18245.get_mcc(self.mcc)

    @property
    def hours(self):
        return [
            x.as_dict() for x in LocationHours.objects.filter(location=self)
        ]

    @property
    def capabilities(self):
        return [
            x.capability
            for x in LocationCapability.objects.filter(location=self)
        ]

    def as_dict(self):
        if not self.postal_code:
            self.link_postal_code()

        return {
            "name": self.name,
            "business_name":
            self.business_name if self.business_name else self.name,
            "capabilities": self.capabilities,
            "coordinates": {
                "latitude": self.latitude,
                "longitude": self.longitude
            },
            "address": {
                "address_line_1": self.address1,
                "address_line_2": self.address2,
                "locality": self.city,
                "administrative_district_level_1":
                self.postal_code.admin_code1,
                "administrative_district_level_2":
                self.postal_code.admin_name2,
                "postal_code": self.zip_code,
                "country": self.postal_code.country_code,
            },
            "business_hours": {
                "periods": [self.hours]
            },
            "description": self.description,
            "business_email": self.email,
            "website_url": self.website_url,
            "facebook_url": self.facebook_url,
        }

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        super(Location, self).save(force_insert, force_update, using,
                                   update_fields)

        location_body = {"location": self.as_dict()}

        if self._state.adding:
            result = square_client.locations.create_location(
                body=location_body)
            if "location" in result:
                self.location_id = result.get("location").get("id")
                super(Location, self).save(force_insert, force_update, using,
                                           update_fields)
        else:
            result = square_client.locations.update_location(
                location_id=self.location_id, body=location_body)
        return result.is_success()

    def download(self):
        result = square_client.locations.retrieve_location(
            location_id=self.location_id)
        if result.is_success():
            location = result.get("location")

            self.name = (location.get("name"), )
            self.business_name = (location.get("business_name"), )
            self.country = (location.get("country"), )
            self.created_at = (parse(location.get("created_at")), )
            self.currency = (location.get("currency"), )
            self.language_code = (location.get("language_code"), )
            self.mcc = (location.get("mcc"), )
            self.merchant_id = (location.get("merchant_id"), )
            self.location_status = (location.get("status"), )
            self.location_type = (location.get("type"), )
            self.address1 = (location.get("address").get("address_line_1"), )
            self.address2 = (location.get("address").get("address_line_2"), )
            self.city = (location.get("address").get("locality"), )
            self.zip_code = (location.get("address").get("postal_code"), )

            capabilities = location.get("capabilities")
            for capability in capabilities:
                try:
                    LocationCapability.objects.get(location=self,
                                                   capability=capability)
                except LocationCapability.DoesNotExist:
                    LocationCapability.objects.create(location=self,
                                                      capability=capability)
            LocationCapability.objects.filter(location=self).exclude(
                capability__in=capabilities).delete()
        return result.is_success()
Ejemplo n.º 11
0
class Answer(Model):
    question = ForeignKey("TestQuestion", on_delete=CASCADE, related_name="answers")
    text = TextField()
    is_correct = BooleanField(default=False)
Ejemplo n.º 12
0
class Townie(User):
    """Both an almost normal Django User as well as an abstraction over a
    system user."""
    class Meta:
        verbose_name = 'Townie'
        verbose_name_plural = 'Townies'

    shell = CharField(max_length=50, default="/bin/bash")
    reviewed = BooleanField(default=False)
    reasons = TextField(blank=True, null=False, default='')
    displayname = CharField(max_length=100, blank=False, null=False)

    def send_welcome_email(self, admin_name='vilmibm'):
        welcome_tmpl = get_template('users/welcome_email.txt')
        context = {
            'username': self.username,
            'admin_name': admin_name,
        }
        text = welcome_tmpl.render(context)
        from_address = '{}@tilde.town'.format(admin_name)
        success = send_email(self.email,
                             text,
                             subject='tilde.town!',
                             frum=from_address)
        if not success:
            Ticket.objects.create(
                name='system',
                email='*****@*****.**',
                issue_type='other',
                issue_text='was not able to send welcome email to {} ({})'.
                format(self.username, self.email))

    # managing concrete system state

    def create_on_disk(self):
        """A VERY NOT IDEMPOTENT create function. Originally, I had ambitions
        to have this be idempotent and able to incrementally update a user as
        needed, but decided that was overkill for now."""
        assert (self.reviewed)
        dot_ssh_path = '/home/{}/.ssh'.format(self.username)

        _guarded_run([
            'sudo',
            'adduser',
            '--quiet',
            '--shell={}'.format(self.shell),
            '--gecos="{}"'.format(self.displayname),
            '--disabled-password',
            self.username,
        ])

        # Create .ssh
        _guarded_run(
            ['sudo', '--user={}'.format(self.username), 'mkdir', dot_ssh_path])

        # Write out authorized_keys file
        # Why is this a call out to a python script? There's no secure way with
        # sudoers to allow this code to write to a file; if this code was to be
        # compromised, the ability to write arbitrary files with sudo is a TKO.
        # By putting the ssh key file creation into its own script, we can just
        # give sudo access for that one command to this code.
        #
        # We could put the other stuff from here into that script and then only
        # grant sudo for the script, but then we're moving code out of this
        # virtual-env contained, maintainable thing into a script. it's my
        # preference to have the script be as minimal as possible.
        with TemporaryFile(dir="/tmp") as fp:
            fp.write(self.generate_authorized_keys().encode('utf-8'))
            fp.seek(0)
            _guarded_run(
                [
                    'sudo', '--user={}'.format(self.username),
                    '/opt/bin/create_keyfile.py', self.username
                ],
                stdin=fp,
            )

    def generate_authorized_keys(self):
        """returns a string suitable for writing out to an authorized_keys
        file"""
        content = KEYFILE_HEADER
        pubkeys = Pubkey.objects.filter(townie=self)
        for key in pubkeys:
            if key.key.startswith('ssh-'):
                content += '\n{}'.format(key.key)
            else:
                content += '\n{} {}'.format(key.key_type, key.key)

        return content
Ejemplo n.º 13
0
class Comment(Model):
    username = CharField(max_length=20)
    message = TextField(max_length=1000)
    order = TextField(max_length=100)
    created = DateTimeField(auto_now_add=True)

    @staticmethod
    def make(request: HttpRequest, form: CommentForm):
        message = form.cleaned_data['message']
        username = request.user.get_username() or 'anonymous'
        order = get_next_order(request.POST['order'])
        new_comment = Comment(username=username, message=message, order=order)
        new_comment.save()
        created = new_comment.created
        return dict(created=created.strftime("%d %B %Y г. %H:%M").lstrip('0'),
                    username=username,
                    message=message,
                    order=order,
                    next=Comment.get_response_order(order))

    @staticmethod
    def last_order():
        try:
            last = Comment.objects.all().order_by('-order')[0].order
            return last.split('_')[0]
        except IndexError:
            return '00000'

    @staticmethod
    def comment_tuples() -> List[namedtuple]:
        return [
            dict2namedtuple(dct)
            for dct in Comment.objects.all().order_by('order').values()
        ]

    @staticmethod
    def get_last_in_dialog(dialog):
        try:
            return Comment.objects.filter(order__startswith=dialog).order_by(
                'order')[1].order[:len(dialog) + 6]
        except IndexError:
            return None

    @staticmethod
    def get_response_order(dialog):
        last = Comment.get_last_in_dialog(dialog)
        last = get_next_order(last) if last else last
        return last or dialog + '_00000'

    @staticmethod
    def next_tuples():
        return [
            Comment.get_response_order(dct['order'])
            for dct in Comment.objects.all().order_by('order').values()
        ]

    @staticmethod
    def get_new_created(last_update):
        result = []
        for i in Comment.objects.filter(created__gt=last_update).values():
            dct = dict(i)
            dct.update({'next': get_next_order(i['order'])})
            result.append(dct)
        return result
Ejemplo n.º 14
0
class Agreement(BaseModel):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    title = TextField()
    content = TextField()
    users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='agreements', through='UserAgreement')
Ejemplo n.º 15
0
class Event(CleanSave, TimestampedModel):
    """An `Event` represents a MAAS event.

    :ivar type: The event's type.
    :ivar node: The node of the event.
    :ivar node_system_id: The system_id of the node of the event.
    :ivar node_hostname: The hostname of the node of the event.
    :ivar user_id: The user's id responsible for this event.
    :ivar username: The username of the user responsible for this event.
    :ivar ip_address: IP address used in the request for this event.
    :ivar endpoint: Endpoint used in the request for this event.
    :ivar user_agent: User agent used in the request for this event.
    :ivar action: The action of the event.
    :ivar description: A free-form description of the event.
    """

    type = ForeignKey("EventType",
                      null=False,
                      editable=False,
                      on_delete=PROTECT)

    # This gets set to None if the node gets deleted from the pre_delete signal
    node = ForeignKey("Node", null=True, editable=False, on_delete=DO_NOTHING)

    node_system_id = CharField(max_length=41,
                               blank=True,
                               null=True,
                               editable=False)

    # Set on node deletion.
    node_hostname = CharField(max_length=255,
                              default="",
                              blank=True,
                              validators=[validate_hostname])

    user_id = IntegerField(blank=True, null=True, editable=False)

    username = CharField(max_length=150, blank=True, default="")

    # IP address of the request that caused this event.
    ip_address = GenericIPAddressField(unique=False,
                                       null=True,
                                       editable=False,
                                       blank=True,
                                       default=None)

    # Endpoint of request used to register the event.
    endpoint = IntegerField(choices=ENDPOINT_CHOICES,
                            editable=False,
                            default=ENDPOINT.API)

    # User agent of request used to register the event.
    user_agent = TextField(default="", blank=True, editable=False)

    action = TextField(default="", blank=True, editable=False)

    description = TextField(default="", blank=True, editable=False)

    objects = EventManager()

    class Meta(DefaultMeta):
        verbose_name = "Event record"
        index_together = (("node", "id"), )
        indexes = [
            # Needed to get the latest event for each node on the
            # machine listing page.
            Index(fields=["node", "-created", "-id"])
        ]

    @property
    def endpoint_name(self):
        return ENDPOINT_CHOICES[self.endpoint][1]

    @property
    def owner(self):
        if self.username:
            return self.username
        else:
            return "unknown"

    @property
    def hostname(self):
        if self.node_hostname:
            return self.node_hostname
        elif self.node is not None:
            return self.node.hostname
        else:
            return "unknown"

    @property
    def render_audit_description(self):
        return self.description % {"username": self.owner}

    def __str__(self):
        return "%s (node=%s, type=%s, created=%s)" % (
            self.id,
            self.node,
            self.type.name,
            self.created,
        )

    def validate_unique(self, exclude=None):
        """Override validate unique so nothing is validated.

        Since `Event` is never checked for user validaton let Postgres
        handle the foreign keys instead of Django pre-checking before save.
        """
        pass
Ejemplo n.º 16
0
class Video(BasePage):
    resource_type = "video"
    parent_page_types = ["Videos"]
    subpage_types = []
    template = "video.html"

    # Content fields
    description = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional short text description, max. 400 characters",
        max_length=400,
    )
    body = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES,
        help_text=(
            "Optional body content. Supports rich text, images, embed via URL, "
            "embed via HTML, and inline code snippets"),
    )
    related_links_mdn = StreamField(
        StreamBlock([("link", ExternalLinkBlock())], required=False),
        null=True,
        blank=True,
        help_text="Optional links to MDN Web Docs for further reading",
        verbose_name="Related MDN links",
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )
    types = CharField(max_length=14, choices=VIDEO_TYPE, default="conference")
    duration = CharField(
        max_length=30,
        blank=True,
        null=True,
        help_text=
        ("Optional video duration in MM:SS format e.g. “12:34”. Shown when the "
         "video is displayed as a card"),
    )
    transcript = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES,
        help_text="Optional text transcript of the video, supports rich text",
    )
    video_url = StreamField(
        StreamBlock([("embed", EmbedBlock())],
                    min_num=1,
                    max_num=1,
                    required=True),
        help_text=
        ("Embed URL for the video e.g. https://www.youtube.com/watch?v=kmk43_2dtn0"
         ),
    )
    speakers = StreamField(
        StreamBlock(
            [("speaker", PageChooserBlock(target_model="people.Person"))],
            required=False,
        ),
        blank=True,
        null=True,
        help_text=
        "Optional list of people associated with or starring in the video",
    )

    # Card fields
    card_title = CharField("Title", max_length=140, blank=True, default="")
    card_description = TextField("Description",
                                 max_length=400,
                                 blank=True,
                                 default="")
    card_image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
        verbose_name="Image",
    )

    # Meta fields
    date = DateField("Upload date", default=datetime.date.today)
    keywords = ClusterTaggableManager(through=VideoTag, blank=True)

    # Content panels
    content_panels = BasePage.content_panels + [
        FieldPanel("description"),
        ImageChooserPanel("image"),
        StreamFieldPanel("video_url"),
        FieldPanel("body"),
        StreamFieldPanel("related_links_mdn"),
        FieldPanel("transcript"),
    ]

    # Card panels
    card_panels = [
        FieldPanel("card_title"),
        FieldPanel("card_description"),
        ImageChooserPanel("card_image"),
    ]

    # Meta panels
    meta_panels = [
        FieldPanel("date"),
        StreamFieldPanel("speakers"),
        MultiFieldPanel(
            [InlinePanel("topics")],
            heading="Topics",
            help_text=
            ("These are the topic pages the video will appear on. The first topic "
             "in the list will be treated as the primary topic and will be shown "
             "in the page’s related content."),
        ),
        FieldPanel("duration"),
        MultiFieldPanel(
            [FieldPanel("types")],
            heading="Type",
            help_text="Choose a video type to help people search for the video",
        ),
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("social_image"),
                FieldPanel("keywords"),
            ],
            heading="SEO",
            help_text=(
                "Optional fields to override the default title and description "
                "for SEO purposes"),
        ),
    ]

    settings_panels = [FieldPanel("slug")]

    # Tabs
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading="Content"),
        ObjectList(card_panels, heading="Card"),
        ObjectList(meta_panels, heading="Meta"),
        ObjectList(settings_panels, heading="Settings", classname="settings"),
    ])

    def get_absolute_url(self):
        # For the RSS feed
        return self.full_url

    @property
    def primary_topic(self):
        """Return the first (primary) topic specified for the video."""
        video_topic = self.topics.first()
        return video_topic.topic if video_topic else None

    @property
    def read_time(self):
        return str(readtime.of_html(str(self.body)))

    @property
    def related_resources(self):
        """Returns resources that are related to the current resource, i.e. live,
        public articles and videos which have the same topics."""
        topic_pks = [topic.topic.pk for topic in self.topics.all()]
        return get_combined_articles_and_videos(
            self, topics__topic__pk__in=topic_pks)

    def has_speaker(self, person):
        for speaker in self.speakers:  # pylint: disable=not-an-iterable
            if str(speaker.value) == str(person.title):
                return True
        return False
Ejemplo n.º 17
0
class VLAN(CleanSave, TimestampedModel):
    """A `VLAN`.

    :ivar name: The short-human-identifiable name for this VLAN.
    :ivar vid: The VLAN ID of this VLAN.
    :ivar fabric: The `Fabric` this VLAN belongs to.
    """

    objects = VLANManager()

    class Meta(DefaultMeta):
        """Needed for South to recognize this model."""
        verbose_name = "VLAN"
        verbose_name_plural = "VLANs"
        unique_together = (
            ('vid', 'fabric'),
        )

    name = CharField(
        max_length=256, editable=True, null=True, blank=True,
        validators=[VLAN_NAME_VALIDATOR])

    description = TextField(null=False, blank=True)

    vid = IntegerField(editable=True)

    fabric = ForeignKey(
        'Fabric', blank=False, editable=True, on_delete=CASCADE)

    mtu = IntegerField(default=DEFAULT_MTU)

    dhcp_on = BooleanField(default=False, editable=True)

    external_dhcp = MAASIPAddressField(
        null=True, editable=False, blank=True, default=None)

    primary_rack = ForeignKey(
        'RackController', null=True, blank=True, editable=True,
        related_name='+', on_delete=CASCADE)

    secondary_rack = ForeignKey(
        'RackController', null=True, blank=True, editable=True,
        related_name='+', on_delete=CASCADE)

    relay_vlan = ForeignKey(
        'self', null=True, blank=True, editable=True,
        related_name='relay_vlans', on_delete=deletion.SET_NULL)

    space = ForeignKey(
        'Space', editable=True, blank=True, null=True, on_delete=SET_NULL)

    def __str__(self):
        return "%s.%s" % (self.fabric.get_name(), self.get_name())

    def clean_vid(self):
        if self.vid is None or self.vid < 0 or self.vid > 4094:
            raise ValidationError(
                {'vid':
                    ["VID must be between 0 and 4094."]})

    def clean_mtu(self):
        # Linux doesn't allow lower than 552 for the MTU.
        if self.mtu < 552 or self.mtu > 65535:
            raise ValidationError(
                {'mtu':
                    ["MTU must be between 552 and 65535."]})

    def clean(self):
        self.clean_vid()
        self.clean_mtu()

    def is_fabric_default(self):
        """Is this the default VLAN in the fabric?"""
        return self.fabric.get_default_vlan() == self

    def get_name(self):
        """Return the name of the VLAN."""
        if self.is_fabric_default():
            return "untagged"
        elif self.name is not None:
            return self.name
        else:
            return str(self.vid)

    def manage_connected_interfaces(self):
        """Deal with connected interfaces:

        - delete all VLAN interfaces.
        - reconnect the other interfaces to the default VLAN of the fabric.
        """
        for interface in self.interface_set.all():
            if isinstance(interface, VLANInterface):
                interface.delete()
            else:
                interface.vlan = self.fabric.get_default_vlan()
                interface.save()

    def manage_connected_subnets(self):
        """Reconnect subnets the default VLAN of the fabric."""
        for subnet in self.subnet_set.all():
            subnet.vlan = self.fabric.get_default_vlan()
            subnet.save()

    def delete(self):
        if self.is_fabric_default():
            raise ValidationError(
                "This VLAN is the default VLAN in the fabric, "
                "it cannot be deleted.")
        self.manage_connected_interfaces()
        self.manage_connected_subnets()
        super(VLAN, self).delete()

    def save(self, *args, **kwargs):
        # Bug 1555759: Raise a Notification if there are no VLANs with DHCP
        # enabled.  Clear it when one gets enabled.
        notifications = Notification.objects.filter(
            ident="dhcp_disabled_all_vlans")
        if self.dhcp_on:
            # No longer true.  Delete the notification.
            notifications.delete()
        elif (not notifications.exists() and
                not VLAN.objects.filter(dhcp_on=True).exists()):
            Notification.objects.create_warning_for_admins(
                "DHCP is not enabled on any VLAN.  This will prevent "
                "machines from being able to PXE boot, unless an external "
                "DHCP server is being used.",
                ident="dhcp_disabled_all_vlans")
        super().save(*args, **kwargs)
Ejemplo n.º 18
0
class Blind(Product):
    name = TextField()
    child_safe = BooleanField(default=False)

    def __str__(self):
        return self.name
Ejemplo n.º 19
0
class HomePage(Page):
    subpage_types = [
        'articles.Articles',
        'content.ContentPage',
        'events.Events',
        'people.People',
        'topics.Topics',
        'videos.Videos',
    ]
    template = 'home.html'

    # Content fields
    subtitle = TextField(max_length=250, blank=True, default='')
    button_text = CharField(max_length=30, blank=True, default='')
    button_url = CharField(max_length=2048, blank=True, default='')
    image = ForeignKey('mozimages.MozImage',
                       null=True,
                       blank=True,
                       on_delete=SET_NULL,
                       related_name='+')
    external_promos = StreamField(
        StreamBlock([
            ('external_promo', FeaturedExternalBlock()),
        ],
                    max_num=2,
                    required=False),
        null=True,
        blank=True,
        help_text=
        'Optional promo space under the header for linking to external sites, max. 2',
    )
    featured = StreamField(
        StreamBlock([
            ('article',
             PageChooserBlock(target_model=(
                 'articles.Article',
                 'externalcontent.ExternalArticle',
             ))),
            ('external_page', FeaturedExternalBlock()),
        ],
                    max_num=4,
                    required=False),
        null=True,
        blank=True,
        help_text='Optional space for featured articles, max. 4',
    )
    about_title = TextField(max_length=250, blank=True, default='')
    about_subtitle = TextField(max_length=250, blank=True, default='')
    about_button_text = CharField(max_length=30, blank=True, default='')
    about_button_url = URLField(max_length=140, blank=True, default='')

    # Card fields
    card_title = CharField('Title', max_length=140, blank=True, default='')
    card_description = TextField('Description',
                                 max_length=400,
                                 blank=True,
                                 default='')
    card_image = ForeignKey(
        'mozimages.MozImage',
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name='+',
        verbose_name='Image',
    )

    # Meta fields
    keywords = ClusterTaggableManager(through=HomePageTag, blank=True)

    # Editor panel configuration
    content_panels = Page.content_panels + [
        MultiFieldPanel([
            FieldPanel('subtitle'),
            FieldPanel('button_text'),
            FieldPanel('button_url'),
        ],
                        heading='Header section',
                        help_text='Optional fields for the header section'),
        MultiFieldPanel(
            [
                ImageChooserPanel('image'),
            ],
            heading='Image',
            help_text=
            'Optional image shown when sharing this page through social media'
        ),
        StreamFieldPanel('external_promos'),
        StreamFieldPanel('featured'),
        MultiFieldPanel(
            [
                FieldPanel('about_title'),
                FieldPanel('about_subtitle'),
                FieldPanel('about_button_text'),
                FieldPanel('about_button_url'),
            ],
            heading='About section',
            help_text='Optional section to explain more about Mozilla'),
    ]

    # Card panels
    card_panels = [
        MultiFieldPanel(
            [
                FieldPanel('card_title'),
                FieldPanel('card_description'),
                ImageChooserPanel('card_image'),
            ],
            heading='Card overrides',
            help_text=
            ('Optional fields to override the default title, description and image when this page is shown as a card'
             )),
    ]

    # Meta panels
    meta_panels = [
        MultiFieldPanel(
            [
                FieldPanel('seo_title'),
                FieldPanel('search_description'),
                FieldPanel('keywords'),
            ],
            heading='SEO',
            help_text=
            'Optional fields to override the default title and description for SEO purposes'
        ),
    ]

    # Settings panels
    settings_panels = [
        FieldPanel('slug'),
    ]

    # Tabs
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(card_panels, heading='Card'),
        ObjectList(meta_panels, heading='Meta'),
        ObjectList(settings_panels, heading='Settings', classname='settings'),
    ])

    @classmethod
    def can_create_at(cls, parent):
        # Allow only one instance of this page type
        return super().can_create_at(parent) and not cls.objects.exists()

    @property
    def primary_topics(self):
        """The site’s top-level topics, i.e. topics without a parent topic."""
        from ..topics.models import Topic
        return Topic.objects.filter(
            parent_topics__isnull=True).live().public().order_by('title')
Ejemplo n.º 20
0
class KeyTextTransform(KeyTransform):
    operator = '->>'
    nested_operator = '#>>'
    output_field = TextField()
Ejemplo n.º 21
0
class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    history = TextField()

    def __str__(self):
        return f'{self.user.username} Profile'
Ejemplo n.º 22
0
class Group(BaseModel, LocationModel, ConversationMixin, DirtyFieldsMixin):
    objects = GroupQuerySet.as_manager()

    name = models.CharField(max_length=settings.NAME_MAX_LENGTH, unique=True)
    description = models.TextField(blank=True)
    welcome_message = models.TextField(blank=True)
    members = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='groups',
        through='GroupMembership',
        through_fields=('group', 'user'),
    )
    public_description = models.TextField(blank=True)
    application_questions = models.TextField(blank=True)
    status = models.CharField(
        default=GroupStatus.ACTIVE.value,
        choices=[(status.value, status.value) for status in GroupStatus],
        max_length=100,
    )
    theme = models.TextField(
        default=GroupTheme.FOODSAVING.value,
        choices=[(theme.value, theme.value) for theme in GroupTheme],
    )
    sent_summary_up_to = DateTimeField(null=True)
    timezone = TimeZoneField(default='Europe/Berlin', null=True, blank=True)
    active_agreement = models.OneToOneField(
        'groups.Agreement',
        related_name='active_group',
        null=True,
        on_delete=models.SET_NULL,
    )
    last_active_at = DateTimeField(default=tz.now)
    is_open = models.BooleanField(default=False)
    photo = VersatileImageField(
        'Group Photo',
        upload_to='group_photos',
        null=True,
    )
    features = ArrayField(TextField(), default=list)

    @property
    def group(self):
        return self

    @property
    def conversation_supports_threads(self):
        return True

    def __str__(self):
        return 'Group {}'.format(self.name)

    def add_member(self, user, added_by=None, history_payload=None):
        membership = GroupMembership.objects.create(
            group=self,
            user=user,
            added_by=added_by,
        )
        History.objects.create(
            typus=HistoryTypus.GROUP_JOIN,
            group=self,
            users=[user],
            payload=history_payload,
        )
        return membership

    def remove_member(self, user):
        History.objects.create(typus=HistoryTypus.GROUP_LEAVE, group=self, users=[user])
        GroupMembership.objects.filter(group=self, user=user).delete()

    def is_member(self, user):
        return not user.is_anonymous and GroupMembership.objects.filter(group=self, user=user).exists()

    def is_editor(self, user):
        return self.is_member_with_role(user, roles.GROUP_EDITOR)

    def is_member_with_role(self, user, role_name):
        return not user.is_anonymous and GroupMembership.objects.filter(
            group=self, user=user, roles__contains=[role_name]
        ).exists()

    def is_playground(self):
        return self.status == GroupStatus.PLAYGROUND.value

    def accept_invite(self, user, invited_by, invited_at):
        self.add_member(
            user,
            added_by=invited_by,
            history_payload={
                'invited_by': invited_by.id,
                'invited_at': invited_at.isoformat(),
                'invited_via': 'e-mail'
            }
        )

    def refresh_active_status(self):
        self.last_active_at = tz.now()
        if self.status == GroupStatus.INACTIVE.value:
            self.status = GroupStatus.ACTIVE.value
        self.save()

    def has_recent_activity(self):
        return self.last_active_at >= tz.now() - timedelta(days=settings.NUMBER_OF_DAYS_UNTIL_GROUP_INACTIVE)

    def get_application_questions_or_default(self):
        return self.application_questions or self.application_questions_default()

    def application_questions_default(self):
        return render_to_string('default_application_questions.nopreview.jinja2')

    def trust_threshold_for_newcomer(self):
        count = getattr(self, '_yesterdays_member_count', None)
        if count is None:
            one_day_ago = timezone.now() - relativedelta(days=1)
            count = self.groupmembership_set.active().filter(created_at__lte=one_day_ago).count()
        dynamic_threshold = max(1, count // 2)
        trust_threshold = min(settings.GROUP_EDITOR_TRUST_MAX_THRESHOLD, dynamic_threshold)
        return trust_threshold

    def active_editors_count(self):
        count = getattr(self, '_active_editors_count', None)
        if count is None:
            count = self.groupmembership_set.active().editors().count()
        return count

    def delete_photo(self):
        if self.photo.name is None:
            return
        # Deletes Image Renditions
        self.photo.delete_all_created_images()
        # Deletes Original Image
        self.photo.delete(save=False)

    def welcome_message_rendered(self, **kwargs):
        return markdown.render(self.welcome_message, **kwargs)
Ejemplo n.º 23
0
class Publishable(Model):
    """
    Base model for Article and Page models.
    """

    preview_id = UUIDField(default=uuid.uuid4)
    revision_id = PositiveIntegerField(default=0, db_index=True)
    head = NullBooleanField(default=None, db_index=True, null=True)

    is_published = NullBooleanField(default=None, db_index=True)
    is_active = NullBooleanField(default=True)

    published_version = PositiveIntegerField(null=True)
    latest_version = PositiveIntegerField(null=True)

    slug = SlugField(max_length=255, db_index=True)

    shares = PositiveIntegerField(default=0, blank=True, null=True)
    views = PositiveIntegerField(default=0)

    featured_image = ForeignKey('ImageAttachment',
                                on_delete=SET_NULL,
                                related_name='%(class)s_featured_image',
                                blank=True,
                                null=True)
    featured_video = ForeignKey('VideoAttachment',
                                on_delete=SET_NULL,
                                related_name='%(class)s_featured_video',
                                blank=True,
                                null=True)

    template = CharField(max_length=255, default='default')
    template_data = JSONField(default={})

    seo_keyword = CharField(max_length=100, null=True)
    seo_description = TextField(null=True)

    integrations = JSONField(default={})

    content = JSONField(default=[])
    snippet = TextField(null=True)

    created_at = DateTimeField()
    updated_at = DateTimeField()
    published_at = DateTimeField(null=True)

    objects = PublishableManager()

    @property
    def template_fields(self):
        if not hasattr(self, '_template_fields'):
            template = self.get_template()
            if template:
                template.set_data(self.template_data)
                self._template_fields = template.prepare_data()
        return self._template_fields

    def add_view(self):
        self.views += 1
        self.save(revision=False)

    def get_template_path(self):
        if self.template != 'default':
            return 'article/%s.html' % self.template
        else:
            return 'article/default.html'

    def get_template(self):
        if not hasattr(self, '_template'):
            from dispatch.theme import ThemeManager

            try:
                self._template = ThemeManager.Templates.get(self.template)
            except:
                self._template = None

        return self._template

    @property
    def html(self):
        """Return HTML representation of content"""
        return content_to_html(self.content, self.id)

    def is_parent(self):
        return self.parent is None

    def publish(self):
        # Unpublish last published version
        type(self).objects.filter(parent=self.parent,
                                  is_published=True).update(is_published=None,
                                                            published_at=None)
        self.is_published = True
        if self.published_at is None:
            self.published_at = timezone.now()
        self.save(revision=False)

        # Set published version for all articles
        type(self).objects.filter(parent=self.parent).update(
            published_version=self.revision_id)
        self.published_version = self.revision_id

        return self

    def unpublish(self):
        type(self).objects.filter(parent=self.parent,
                                  is_published=True).update(is_published=None,
                                                            published_at=None)
        self.is_published = None

        # Unset published version for all articles
        type(self).objects.filter(parent=self.parent).update(
            published_version=None)
        self.published_version = None

        return self

    # Overriding
    @transaction.atomic
    def save(self, revision=True, *args, **kwargs):
        """
        Handles the saving/updating of a Publishable instance.

        Arguments:
        revision - if True, a new version of this Publishable will be created.
        """

        if revision:
            # If this is a revision, set it to be the head of the list and increment the revision id
            self.head = True
            self.revision_id += 1

            previous_revision = self.get_previous_revision()

            if not self.is_parent():
                # If this is a revision, delete the old head of the list.
                type(self).objects \
                    .filter(parent=self.parent, head=True) \
                    .update(head=None)

                # Clear the instance id to force Django to save a new instance.
                # Both fields (pk, id) required for this to work -- something to do with model inheritance
                self.pk = None
                self.id = None

                # New version is unpublished by default
                self.is_published = None

        # Set created_at to current time, but only for first version
        if not self.created_at:
            self.created_at = timezone.now()
            self.updated_at = timezone.now()

        if revision:
            self.updated_at = timezone.now()

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

        # Update the parent foreign key
        if not self.parent:
            self.parent = self
            super(Publishable, self).save(update_fields=['parent'])

        if revision:
            # Set latest version for all articles
            type(self).objects \
                .filter(parent=self.parent) \
                .update(latest_version=self.revision_id)

            self.latest_version = self.revision_id

        return self

    # Overriding delete the parent article to cascade delete all versions
    def delete(self, *args, **kwargs):
        if self.parent == self:
            return super(Publishable, self).delete(*args, **kwargs)

        return self.parent.delete()

    def save_featured_image(self, data):
        """
        Handles saving the featured image.

        If data is None, the featured image will be removed.

        `data` should be dictionary with the following format:
          {
            'image_id': int,
            'caption': str,
            'credit': str
          }
        """

        attachment = self.featured_image

        if data is None:
            if attachment:
                attachment.delete()

            self.featured_image = None
            return

        if data['image_id'] is None:
            if attachment:
                attachment.delete()

            self.featured_image = None
            return

        if not attachment:
            attachment = ImageAttachment()

        attachment.image_id = data.get('image_id', attachment.image_id)
        attachment.caption = data.get('caption', None)
        attachment.credit = data.get('credit', None)

        instance_type = str(type(self)).lower()

        setattr(attachment, instance_type, self)

        attachment.save()

        self.featured_image = attachment

    def save_featured_video(self, data):
        attachment = self.featured_video

        if data is None:
            if attachment:
                attachment.delete()

            self.featured_video = None
            return

        if data['video_id'] is None:
            if attachment:
                attachment.delete()

            self.featured_video = None
            return

        if not attachment:
            attachment = VideoAttachment()

        attachment.video_id = data.get('video_id', attachment.video_id)
        attachment.caption = data.get('caption', None)
        attachment.credit = data.get('credit', None)

        instance_type = str(type(self)).lower()

        setattr(attachment, instance_type, self)

        attachment.save()

        self.featured_video = attachment

    def get_previous_revision(self):
        if self.parent == self:
            return self
        try:
            revision = type(self).objects \
                .filter(parent=self.parent) \
                .order_by('-pk')[1]
            return revision
        except:
            return self

    class Meta:
        abstract = True
Ejemplo n.º 24
0
class UploadedSingleImages(Model):

    # Fix pluralization in admin panel
    class Meta:
        verbose_name_plural = "Uploaded Single Images"

    # Define image categories to be displayed under in ~/templates/our-work.html
    CATEGORIES = (
        ('No_Category', 'Select a Category'),
        ('House_Wash', 'House Wash'),
        ('Wood_Restoring', 'Wood Restoring'),
        ('Oxidation_Removal', 'Oxidation Removal'),
        ('Stain_Removal', 'Stain Removal'),
    )

    DEGREES = (
        (0, '0 degrees'),
        (270, '90 degrees (90 degrees clockwise)'),
        (180, '180 degrees (upside-down)'),
        (90, '270 degrees (90 degrees counter-clockwise)'),
    )

    # Define the user image input fields in the Django admin panel
    Category = CharField(max_length=64,
                         null=True,
                         choices=CATEGORIES,
                         default='No_Category')
    Single_Picture_Description = CharField(max_length=64,
                                           null=True,
                                           blank=True)
    Single_Picture_Size_kB = IntegerField(null=True, default=140)
    Single_Picture_Max_Dimension = IntegerField(null=True, default=768)
    Single_Picture_Rotation = IntegerField(null=True,
                                           choices=DEGREES,
                                           default=0)
    Single_Picture = ImageField(upload_to='images/', null=True)
    date = DateTimeField(auto_now_add=True, null=True)
    Notes = TextField(max_length=200, null=True, blank=True)

    # Add some extra functionality to the default behavior of the *.save() method
    # via the *.super() method
    def save(self, *args, **kwargs):
        if self.Single_Picture:

            # Note: this will overwrite the image uploaded by the user
            self.Single_Picture = self.resize_image(
                self.Single_Picture, self.Single_Picture_Size_kB,
                self.Single_Picture_Max_Dimension,
                self.Single_Picture_Rotation)
        super(UploadedSingleImages, self).save(*args, **kwargs)

    # Resize user-uploaded images
    # https://stackoverflow.com/questions/3723220/how-do-you-convert-a-pil-image-to-a-django-file
    def resize_image(self, picture, size_target, max_dim, rotation):

        # Set variables for the *.binary_search() method
        size_target = size_target * 1000  # Ideal image size (in bytes)
        dimensions = [(max_dim, max_dim)]  # Dimensions for *.thumbnail()
        dimension_factor = 1  # For generating 1x, 2x (retina), or higher res.
        i = 1  # Iteration starting point
        max_i = 7  # Max number of iterations
        quality = 50  # Starting quality value
        L = 1  # Left pointer
        R = 100  # Right pointer

        # Run the binary search algorithm once for each set of dimensions you want to
        # create images at, ie. 320, 576, 768, etc. Currently there is no implementation
        # on the front-end to support more than one set of dimensions, but I'm keeping
        # the FOR loop here anyways so I know where to start if I implement multiple
        # dimensions later in order to support responsive images.
        for dimension in dimensions:
            im_buffer = self.binary_search(picture, size_target, dimension,
                                           dimension_factor, rotation, i,
                                           max_i, quality, L, R)

        # When files are uploaded in Django they are stored in a dictionary called
        # request.FILES as "UploadedFile" objects (or a subclass like
        # InMemoryUploadedFile). We can try to grab the BytesIO object and convert it
        # back into a File object (or "Django" File object) while the BytesIO object
        # is in memory, ie. while it exists within this function.
        #
        # picture.name: *.name is a Django File object attribute that includes the
        # name of the file plus its relative path from MEDIA_ROOT
        #
        # Syntax:
        # InMemoryUploadedFile(file, field_name, name, content_type, size, charset)
        if im_buffer is not None:
            im_resized_file = InMemoryUploadedFile(
                im_buffer, None, picture.name, 'image/jpeg',
                im_buffer.getbuffer().nbytes, None)
            return im_resized_file
        else:
            print("{} was not altered".format(picture))
            return picture

    # Binary search algorithm that uses 3 pointers -- L, R, and quality, where the
    # value for quality is used by PIL's *.save() method to set the quality of an
    # image -- in an attempt to find a quality that produces an image with an file
    # size that is as close to the value for size_target as max_i number of
    # iterations will allow (close, but not perfect, could be memoized I think).
    def binary_search(self,
                      picture,
                      size_target,
                      dimension,
                      dimension_factor,
                      rotation,
                      i,
                      max_i,
                      quality,
                      L,
                      R,
                      im_buffer=None):

        # It's possible that the picture file size is already less than the target
        # file size, but we can still rotate the image here.
        if picture.size < size_target:
            print("{} is already less than {} bytes".format(
                picture, size_target))
            im = Image.open(picture)
            if rotation == 90:
                im = im.transpose(Image.ROTATE_90)
            elif rotation == 180:
                im = im.transpose(Image.ROTATE_180)
            elif rotation == 270:
                im = im.transpose(Image.ROTATE_270)
            im_buffer = BytesIO()
            im.save(im_buffer, "JPEG", quality=quality)
            return im_buffer

        # If the maximum number of iterations have been reached, return
        if i > max_i:
            print("Max iterations have been reached for {}".format(picture))
            return im_buffer

        # Open the image file, alter its dimensions, and save it as a new BytesIO file
        # named 'im_buffer'.
        if quality <= 95:
            im = Image.open(picture)
            if rotation == 90:
                im = im.transpose(Image.ROTATE_90)
            elif rotation == 180:
                im = im.transpose(Image.ROTATE_180)
            elif rotation == 270:
                im = im.transpose(Image.ROTATE_270)
            new_dimension = (dimension[0] * dimension_factor,
                             dimension[1] * dimension_factor)
            im.thumbnail(new_dimension, Image.ANTIALIAS)
            # new_prefix = '{}x-'.format(dimension_factor)
            # new_name = new_prefix + name + '-' + str(dimension[0]) + '.jpg'
            im_buffer = BytesIO()
            im.save(im_buffer, "JPEG", quality=quality)

            # Use L and R pointers to move closer to a value for the 'quality' parameter
            # that produces an image with a file size, in bytes, as close to size_target
            # as possible using a binary search-type of algorithm.
            if im_buffer.getbuffer().nbytes < size_target:
                print(
                    'Resulting image size is LESS    than {} bytes:'.format(
                        size_target),
                    im_buffer.getbuffer().nbytes, 'bytes, quality =', quality)
                L = quality
                quality = int((R + L) / 2)
                return self.binary_search(picture, size_target, dimension,
                                          dimension_factor, rotation, i + 1,
                                          max_i, quality, L, R, im_buffer)
            elif im_buffer.getbuffer().nbytes > size_target:
                print(
                    'Resulting image size is GREATER than {} bytes:'.format(
                        size_target),
                    im_buffer.getbuffer().nbytes, 'bytes, quality =', quality)
                R = quality
                quality = int((R + L) / 2)
                return self.binary_search(picture, size_target, dimension,
                                          dimension_factor, rotation, i + 1,
                                          max_i, quality, L, R, im_buffer)
            else:
                print(
                    'Resulting image size EQUALS {} bytes:'.format(
                        size_target),
                    im_buffer.getbuffer().nbytes, 'bytes, quality =', quality)
                return im_buffer
        else:
            return im_buffer
Ejemplo n.º 25
0
class AsWKT(GeoFunc):
    output_field = TextField()
    arity = 1
Ejemplo n.º 26
0
class ValuesTransform(Transform):
    lookup_name = "values"
    function = "avals"
    output_field = ArrayField(TextField())
Ejemplo n.º 27
0
class Event(BasePage):
    resource_type = "event"
    parent_page_types = ["events.Events"]
    subpage_types = []
    template = "event.html"

    # Content fields
    description = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional short text description, max. 400 characters",
        max_length=400,
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )
    body = CustomStreamField(
        blank=True,
        null=True,
        help_text=(
            "Optional body content. Supports rich text, images, embed via URL, "
            "embed via HTML, and inline code snippets"
        ),
    )
    agenda = StreamField(
        StreamBlock([("agenda_item", AgendaItemBlock())], required=False),
        blank=True,
        null=True,
        help_text="Optional list of agenda items for this event",
    )
    speakers = StreamField(
        StreamBlock(
            [
                ("speaker", PageChooserBlock(target_model="people.Person")),
                ("external_speaker", ExternalSpeakerBlock()),
            ],
            required=False,
        ),
        blank=True,
        null=True,
        help_text="Optional list of speakers for this event",
    )

    # Card fields
    card_title = CharField("Title", max_length=140, blank=True, default="")
    card_description = TextField("Description", max_length=400, blank=True, default="")
    card_image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
        verbose_name="Image",
    )

    # Meta fields
    start_date = DateField(default=datetime.date.today)
    end_date = DateField(blank=True, null=True)
    latitude = FloatField(blank=True, null=True)
    longitude = FloatField(blank=True, null=True)
    register_url = URLField("Register URL", blank=True, null=True)
    venue_name = CharField(max_length=100, blank=True, default="")
    venue_url = URLField("Venue URL", max_length=100, blank=True, default="")
    address_line_1 = CharField(max_length=100, blank=True, default="")
    address_line_2 = CharField(max_length=100, blank=True, default="")
    address_line_3 = CharField(max_length=100, blank=True, default="")
    city = CharField(max_length=100, blank=True, default="")
    state = CharField("State/Province/Region", max_length=100, blank=True, default="")
    zip_code = CharField("Zip/Postal code", max_length=100, blank=True, default="")
    country = CountryField(blank=True, default="")
    keywords = ClusterTaggableManager(through=EventTag, blank=True)

    # Content panels
    content_panels = BasePage.content_panels + [
        FieldPanel("description"),
        MultiFieldPanel(
            [ImageChooserPanel("image")],
            heading="Image",
            help_text=(
                "Optional header image. If not specified a fallback will be used. "
                "This image is also shown when sharing this page via social media"
            ),
        ),
        StreamFieldPanel("body"),
        StreamFieldPanel("agenda"),
        StreamFieldPanel("speakers"),
    ]

    # Card panels
    card_panels = [
        FieldPanel("card_title"),
        FieldPanel("card_description"),
        ImageChooserPanel("card_image"),
    ]

    # Meta panels
    meta_panels = [
        MultiFieldPanel(
            [
                FieldPanel("start_date"),
                FieldPanel("end_date"),
                FieldPanel("latitude"),
                FieldPanel("longitude"),
                FieldPanel("register_url"),
            ],
            heading="Event details",
            classname="collapsible",
            help_text=mark_safe(
                "Optional time and location information for this event. Latitude and "
                "longitude are used to show a map of the event’s location. For more "
                "information on finding these values for a given location, "
                "'<a href='https://support.google.com/maps/answer/18539'>"
                "see this article</a>"
            ),
        ),
        MultiFieldPanel(
            [
                FieldPanel("venue_name"),
                FieldPanel("venue_url"),
                FieldPanel("address_line_1"),
                FieldPanel("address_line_2"),
                FieldPanel("address_line_3"),
                FieldPanel("city"),
                FieldPanel("state"),
                FieldPanel("zip_code"),
                FieldPanel("country"),
            ],
            heading="Event address",
            classname="collapsible",
            help_text=(
                "Optional address fields. The city and country are also shown "
                "on event cards"
            ),
        ),
        MultiFieldPanel(
            [InlinePanel("topics")],
            heading="Topics",
            help_text=(
                "These are the topic pages the event will appear on. The first topic "
                "in the list will be treated as the primary topic and will be shown "
                "in the page’s related content."
            ),
        ),
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("social_image"),
                FieldPanel("keywords"),
            ],
            heading="SEO",
            help_text=(
                "Optional fields to override the default title and description "
                "for SEO purposes"
            ),
        ),
    ]

    # Settings panels
    settings_panels = [FieldPanel("slug")]

    edit_handler = TabbedInterface(
        [
            ObjectList(content_panels, heading="Content"),
            ObjectList(card_panels, heading="Card"),
            ObjectList(meta_panels, heading="Meta"),
            ObjectList(settings_panels, heading="Settings", classname="settings"),
        ]
    )

    @property
    def is_upcoming(self):
        """Returns whether an event is in the future."""
        return self.start_date > datetime.date.today()

    @property
    def primary_topic(self):
        """Return the first (primary) topic specified for the event."""
        article_topic = self.topics.first()
        return article_topic.topic if article_topic else None

    @property
    def month_group(self):
        return self.start_date.replace(day=1)

    @property
    def country_group(self):
        return (
            {"slug": self.country.code.lower(), "title": self.country.name}
            if self.country
            else {"slug": ""}
        )

    @property
    def event_dates(self):
        """Return a formatted string of the event start and end dates"""
        event_dates = self.start_date.strftime("%b %-d")
        if self.end_date and self.end_date != self.start_date:
            event_dates += " &ndash; "
            start_month = self.start_date.strftime("%m")
            if self.end_date.strftime("%m") == start_month:
                event_dates += self.end_date.strftime("%-d")
            else:
                event_dates += self.end_date.strftime("%b %-d")
        return event_dates

    @property
    def event_dates_full(self):
        """Return a formatted string of the event start and end dates,
        including the year"""
        return self.event_dates + self.start_date.strftime(", %Y")

    def has_speaker(self, person):
        for speaker in self.speakers:  # pylint: disable=not-an-iterable
            if speaker.block_type == "speaker" and str(speaker.value) == str(
                person.title
            ):
                return True
        return False
Ejemplo n.º 28
0
class KeysTransform(Transform):
    lookup_name = "keys"
    function = "akeys"
    output_field = ArrayField(TextField())
Ejemplo n.º 29
0
class CatalogItem(Model):
    catalog = ForeignKey(Catalog, blank=True, null=True, on_delete=CASCADE)
    name = CharField(max_length=255, blank=True, null=True)
    description = TextField(blank=True, null=True)
    item_abbreviation = CharField(max_length=255, blank=True, null=True)
    item_key = UUIDField(blank=True, null=True)
    item_id = CharField(max_length=255, blank=True, null=True)
    object_id = CharField(max_length=255, blank=True, null=True)

    def __str__(self):
        return self.name

    def update_id_mappings(self, id_mappings=[]):
        for id_mapping in id_mappings:
            object_id = id_mapping.get("client_object_id ")
            try:
                variant = CatalogVariant.objects.get(catalog_item=self,
                                                     variant_key=object_id)
            except CatalogVariant.DoesNotExist:
                pass
            else:
                variant.object_id = object_id
                variant.save_id()

    def delete(self, using=None, keep_parents=False):
        super().delete(using, keep_parents)

        result = square_client.catalog.delete_catalog_object(
            object_id=self.object_id)
        response = result.body if result.is_success() else result.errors
        log_message(response, pretty=True)

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        if not self.item_abbreviation or self.item_abbreviation is None:
            self.item_abbreviation = generate_abbreviation(self.name)

        if not self.item_key or self.item_key is None:
            self.item_key = str(uuid0.generate())

        if not self.item_id:
            self.item_id = "#{}".format(slugify(self.name))
            self.object_id = "#{}".format(slugify(self.name))

        super().save(force_insert, force_update, using, update_fields)

        itemid = self.item_id
        if not self._state.adding:
            if self.object_id is not None:
                itemid = self.object_id

        body = self.as_dict(itemid)

        log_message(body, pretty=True)

        if self.variants.count() > 0:
            result = square_client.catalog.upsert_catalog_object(body=body)
            catalog_item = result.body if result.is_success(
            ) else result.errors

            if "catalog_object" in catalog_item:
                self.catalog.version = catalog_item.get("catalog_object").get(
                    "version")
                self.object_id = catalog_item.get("catalog_object").get("id")
                super().save(force_insert, force_update, using, update_fields)

            try:
                id_mappings = catalog_item.get("id_mappings", [])
            except AttributeError:
                log_message(catalog_item, pretty=True)
            else:
                self.update_id_mappings(id_mappings)

    @property
    def idempotency_key(self):
        return str(uuid0.generate())

    @property
    def variants(self):
        return CatalogVariant.objects.filter(catalog_item=self)

    @property
    def abbreviation(self):
        pieces = self.name.split()
        return self.name[0:2] if len(pieces) == 1 else "".join(
            [x[0] for x in pieces])

    def get_item(self):
        version = self.catalog.version
        if not version:
            result = square_client.catalog.retrieve_catalog_object(
                object_id=self.item_key)
        else:
            result = square_client.catalog.retrieve_catalog_object(
                object_id=self.item_key, catalog_version=version)

        item = result.body if result.is_success() else result.errors
        if "object" in item:
            item = item.get("object")

        return item

    def as_dict(self, item_id):
        variations = [variant.as_dict() for variant in self.variants]

        return {
            "idempotency_key": self.idempotency_key,
            "object": {
                "type": "ITEM",
                "id": item_id,
                "item_data": {
                    "name": self.name,
                    "description": self.description,
                    "abbreviation": self.item_abbreviation,
                    "variations": variations,
                },
            },
        }
Ejemplo n.º 30
0
class Space(CleanSave, TimestampedModel):
    """A `Space`.

    :ivar name: The short-human-identifiable name for this space.
    :ivar objects: An instance of the class :class:`SpaceManager`.
    """

    # Name of the undefined space.
    UNDEFINED = "undefined"

    class Meta(DefaultMeta):
        """Needed for South to recognize this model."""
        verbose_name = "Space"
        verbose_name_plural = "Spaces"

    objects = SpaceManager()

    # We don't actually allow blank or null name, but that is enforced in
    # clean() and save().
    name = CharField(max_length=256,
                     editable=True,
                     null=True,
                     blank=True,
                     unique=True,
                     validators=[validate_space_name])

    description = TextField(null=False, blank=True)

    def __str__(self):
        return "name=%s" % self.get_name()

    def is_default(self):
        """Is this the default space?"""
        return self.id == 0

    def get_name(self):
        """Return the name of the space."""
        if self.name:
            return self.name
        else:
            return "space-%s" % self.id

    def clean_name(self):
        reserved = re.compile('^space-\d+$')
        if self.name is not None and self.name != '':
            if self.name == Space.UNDEFINED:
                raise ValidationError({'name': ["Reserved space name."]})
            if reserved.search(self.name):
                if self.id is None or self.name != 'space-%d' % self.id:
                    raise ValidationError({'name': ["Reserved space name."]})
        elif self.id is not None:
            # Since we are not creating the space, force the (null or empty)
            # name to be the default name.
            self.name = "space-%d" % self.id

    def save(self, *args, **kwargs):
        # Name will get set by clean_name() if None or empty, and there is an
        # id. We just need to handle names here for creation.
        super().save(*args, **kwargs)
        if self.name is None or self.name == '':
            # If we got here, then we have a newly created space that needs a
            # default name.
            self.name = "space-%d" % self.id
            self.save()

    def clean(self, *args, **kwargs):
        super(Space, self).clean(*args, **kwargs)
        self.clean_name()

    @property
    def subnet_set(self):
        """Backward compatibility shim to get the subnets on this space."""
        # Circular imports.
        from maasserver.models import Subnet
        return Subnet.objects.filter(vlan__space=self)
Ejemplo n.º 31
0
class TestQuestion(Model):
    test = ForeignKey("Test", on_delete=CASCADE, related_name="questions")
    text = TextField()
Ejemplo n.º 32
0
class Base(CremeEntity):
    name = CharField(_('Name'), max_length=100)
    number = CharField(_('Number'), max_length=100, blank=True)
    issuing_date     = DateField(_('Issuing date'), blank=True, null=True)\
                                .set_tags(optional=True)
    expiration_date  = DateField(_('Expiration date'), blank=True, null=True)\
                                .set_tags(optional=True)
    discount = BillingDiscountField(
        _('Overall discount'),
        default=DEFAULT_DECIMAL,
        max_digits=10,
        decimal_places=2,
    )
    billing_address = ForeignKey(
        settings.PERSONS_ADDRESS_MODEL,
        verbose_name=_('Billing address'),
        related_name='+',
        blank=True,
        null=True,
        editable=False,
        on_delete=SET_NULL,
    ).set_tags(enumerable=False)
    shipping_address = ForeignKey(
        settings.PERSONS_ADDRESS_MODEL,
        verbose_name=_('Shipping address'),
        related_name='+',
        blank=True,
        null=True,
        editable=False,
        on_delete=SET_NULL,
    ).set_tags(enumerable=False)
    currency = ForeignKey(
        Currency,
        verbose_name=_('Currency'),
        related_name='+',
        default=DEFAULT_CURRENCY_PK,
        on_delete=PROTECT,
    )
    comment = TextField(_('Comment'), blank=True).set_tags(optional=True)
    total_vat = MoneyField(
        _('Total with VAT'),
        default=0,
        max_digits=14,
        decimal_places=2,
        blank=True,
        null=True,
        editable=False,
    )
    total_no_vat = MoneyField(
        _('Total without VAT'),
        default=0,
        max_digits=14,
        decimal_places=2,
        blank=True,
        null=True,
        editable=False,
    )
    additional_info = ForeignKey(
        AdditionalInformation,
        verbose_name=_('Additional Information'),
        related_name='+',
        blank=True,
        null=True,
        # on_delete=SET_NULL,
        on_delete=CREME_REPLACE_NULL,
    ).set_tags(clonable=False, optional=True)
    payment_terms = ForeignKey(
        PaymentTerms,
        verbose_name=_('Payment Terms'),
        related_name='+',
        blank=True,
        null=True,
        # on_delete=SET_NULL,
        on_delete=CREME_REPLACE_NULL,
    ).set_tags(clonable=False, optional=True)
    payment_info = ForeignKey(
        PaymentInformation,
        verbose_name=_('Payment information'),
        blank=True,
        null=True,
        editable=False,
        on_delete=SET_NULL,
    ).set_tags(optional=True)

    creation_label = _('Create an accounting document')

    generate_number_in_create = True  # TODO: use settings instead ???

    # Caches
    _creditnotes_cache = None

    class Meta:
        abstract = True
        manager_inheritance_from_future = True
        app_label = 'billing'
        ordering = ('name', )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._lines_cache = {
        }  # Key: Line class ; Value: Lines instances (list)

    def __str__(self):
        return self.name

    def _pre_delete(self):
        lines = [*self.iter_all_lines()]

        for relation in Relation.objects.filter(type__in=[
                REL_SUB_BILL_ISSUED,
                REL_SUB_BILL_RECEIVED,
                REL_SUB_HAS_LINE,
                REL_OBJ_LINE_RELATED_ITEM,
        ],
                                                subject_entity=self.id):
            relation._delete_without_transaction()

        for line in lines:
            line._delete_without_transaction()

    def invalidate_cache(self):
        self._lines_cache.clear()
        self._creditnotes_cache = None

    # TODO: property + cache
    # TODO: factorise with get_target()
    # TODO: return an Organisation instead of a CremeEntity ?? <- If doing this check calls to .get_source().get_real_entity()
    def get_source(self):
        try:
            return Relation.objects.get(
                subject_entity=self.id,
                type=REL_SUB_BILL_ISSUED).object_entity if self.id else None
        except Relation.DoesNotExist:
            return None

    def get_target(self):
        try:
            return Relation.objects.get(
                subject_entity=self.id,
                type=REL_SUB_BILL_RECEIVED).object_entity if self.id else None
        except Relation.DoesNotExist:
            return None

    def get_credit_notes(self):
        credit_notes = self._creditnotes_cache

        if credit_notes is None:
            self._creditnotes_cache = credit_notes = []

            if self.id:
                relations = Relation.objects.filter(subject_entity=self.id,
                                                    type=REL_OBJ_CREDIT_NOTE_APPLIED,
                                                   ) \
                                            .select_related('object_entity')
                Relation.populate_real_object_entities(relations)
                credit_notes.extend(rel.object_entity.get_real_entity()
                                    for rel in relations
                                    if not rel.object_entity.is_deleted)

        return credit_notes

    def generate_number(self, source=None):
        from creme.billing.registry import algo_registry  # Lazy loading of number generators

        if source is None:
            source = self.get_source()
        self.number = 0

        if source:
            real_content_type = self.entity_type

            try:
                name_algo = ConfigBillingAlgo.objects.get(
                    organisation=source, ct=real_content_type).name_algo
                algo = algo_registry.get_algo(name_algo)
                self.number = algo().generate_number(source, real_content_type)
            except Exception as e:
                logger.debug('Exception during billing.generate_number(): %s',
                             e)

    def get_lines(self, klass):
        assert not klass._meta.abstract, '"klass" cannot be an abstract model (use ProductLine or ServiceLine)'

        cache = self._lines_cache
        lines = cache.get(klass)

        if lines is None:
            lines = cache[klass] = klass.objects.filter(
                relations__object_entity=self.id,
                relations__type=REL_OBJ_HAS_LINE,
            )

        return lines

    def iter_all_lines(self):
        from ..registry import lines_registry

        for line_cls in lines_registry:
            yield from self.get_lines(line_cls)

    def _get_lines_total_n_creditnotes_total(self):
        creditnotes_total = sum(credit_note.total_no_vat
                                for credit_note in self.get_credit_notes())
        lines_total = sum(
            l.get_price_exclusive_of_tax(self) for l in self.iter_all_lines())

        return lines_total, creditnotes_total

    def _get_lines_total_n_creditnotes_total_with_tax(self):
        creditnotes_total = sum(credit_note.total_vat
                                for credit_note in self.get_credit_notes())
        lines_total_with_tax = sum(
            l.get_price_inclusive_of_tax(self) for l in self.iter_all_lines())

        return lines_total_with_tax, creditnotes_total

    def _get_total(self):
        lines_total, creditnotes_total = self._get_lines_total_n_creditnotes_total(
        )

        return max(DEFAULT_DECIMAL, lines_total - creditnotes_total)

    def _get_total_with_tax(self):
        lines_total_with_tax, creditnotes_total = self._get_lines_total_n_creditnotes_total_with_tax(
        )

        return max(DEFAULT_DECIMAL, lines_total_with_tax - creditnotes_total)

    def _pre_save_clone(self, source):
        if self.generate_number_in_create:
            self.generate_number(source.get_source())
        else:
            self.number = ''

    def _copy_relations(self, source):
        from ..registry import relationtype_converter
        # Not REL_OBJ_CREDIT_NOTE_APPLIED, links to CreditNote are not cloned.
        relation_create = Relation.objects.create
        class_map = relationtype_converter.get_class_map(source, self)
        super()._copy_relations(
            source,
            allowed_internal=[REL_SUB_BILL_ISSUED, REL_SUB_BILL_RECEIVED])

        for relation in source.relations.filter(type__is_internal=False,
                                                type__is_copiable=True,
                                                type__in=class_map.keys()):
            relation_create(
                user_id=relation.user_id,
                subject_entity=self,
                type=class_map[relation.type],
                object_entity_id=relation.object_entity_id,
            )

    def _post_clone(self, source):
        source.invalidate_cache()

        for line in source.iter_all_lines():
            line.clone(self)

    # TODO: factorise with persons ??
    def _post_save_clone(self, source):
        save = False

        if source.billing_address is not None:
            self.billing_address = source.billing_address.clone(self)
            save = True

        if source.shipping_address is not None:
            self.shipping_address = source.shipping_address.clone(self)
            save = True

        if save:
            self.save()

    # TODO: Can not we really factorise with clone()
    def build(self, template):
        self._build_object(template)
        self._post_save_clone(template)  # Copy addresses
        self._post_clone(template)  # Copy lines
        self._build_relations(template)
        self._build_properties(template)
        return self

    def _build_object(self, template):
        logger.debug("=> Clone base object")
        today = date.today()
        self.user = template.user
        self.name = template.name
        self.number = template.number
        self.issuing_date = today
        self.expiration_date = today
        self.discount = template.discount
        self.currency = template.currency
        self.comment = template.comment
        self.payment_info = template.payment_info
        self.save()

        # NB: not copied:
        # - additional_info
        # - payment_terms

    def _build_relations(self, template):
        logger.debug("=> Clone relations")
        self._copy_relations(template)

    def _build_properties(self, template):
        logger.debug("=> Clone properties")
        self._copy_properties(template)

    def save(self, *args, **kwargs):
        if self.pk:
            self.invalidate_cache()

            self.total_vat = self._get_total_with_tax()
            self.total_no_vat = self._get_total()

        return super().save(*args, **kwargs)
Ejemplo n.º 33
0
class simics_memory_diff(Model):
    checkpoint = IntegerField()
    block = TextField()
    image_index = IntegerField()
    result = ForeignKey(result)
Ejemplo n.º 34
0
 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
     kwargs.pop('max_length', None)
     self.verify_exists = verify_exists
     TextField.__init__(self, verbose_name, name, **kwargs)
Ejemplo n.º 35
0
class injection(Model):
    bit = IntegerField(null=True)
    checkpoint = IntegerField(null=True)
    config_object = TextField(null=True)
    field = TextField(null=True)
    gold_value = TextField(null=True)
    injected_value = TextField(null=True)
    processor_mode = TextField(null=True)
    register = TextField(null=True)
    register_access = TextField(null=True)
    register_alias = TextField(null=True)
    register_index = ArrayField(IntegerField(), null=True)
    result = ForeignKey(result)
    success = BooleanField()
    target = TextField(null=True)
    target_index = IntegerField(null=True)
    target_name = TextField(null=True)
    time = FloatField(null=True)
    timestamp = DateTimeField(auto_now_add=True)
    tlb_entry = TextField(null=True)
Ejemplo n.º 36
0
class Event(CleanSave, TimestampedModel):
    """An `Event` represents a MAAS event.

    :ivar type: The event's type.
    :ivar node: The node of the event.
    :ivar node_hostname: The hostname of the node of the event.
    :ivar user: The user responsible for this event.
    :ivar username: The username of the user responsible for this event.
    :ivar ip_address: IP address used in the request for this event.
    :ivar endpoint: Endpoint used in the request for this event.
    :ivar user_agent: User agent used in the request for this event.
    :ivar action: The action of the event.
    :ivar description: A free-form description of the event.
    """

    type = ForeignKey('EventType',
                      null=False,
                      editable=False,
                      on_delete=PROTECT)

    node = ForeignKey('Node', null=True, editable=False, on_delete=SET_NULL)

    # Set on node deletion.
    node_hostname = CharField(max_length=255,
                              default='',
                              blank=True,
                              validators=[validate_hostname])

    user = ForeignKey(User,
                      default=None,
                      blank=True,
                      null=True,
                      editable=False,
                      on_delete=SET_NULL)

    # Set on user deletion.
    username = CharField(max_length=32, blank=True, default='')

    # IP address of the request that caused this event.
    ip_address = MAASIPAddressField(unique=False,
                                    null=True,
                                    editable=False,
                                    blank=True,
                                    default=None)

    # Endpoint of request used to register the event.
    endpoint = IntegerField(choices=ENDPOINT_CHOICES,
                            editable=False,
                            default=ENDPOINT.API)

    # User agent of request used to register the event.
    user_agent = TextField(default='', blank=True, editable=False)

    action = TextField(default='', blank=True, editable=False)

    description = TextField(default='', blank=True, editable=False)

    objects = EventManager()

    class Meta(DefaultMeta):
        verbose_name = "Event record"
        index_together = (("node", "id"), )

    @property
    def endpoint_name(self):
        return ENDPOINT_CHOICES[self.endpoint][1]

    @property
    def render_audit_description(self):
        if self.username:
            return self.description % {'username': self.username}
        else:
            return self.description % {'username': self.user.username}

    def __str__(self):
        return "%s (node=%s, type=%s, created=%s)" % (
            self.id, self.node, self.type.name, self.created)
Ejemplo n.º 37
0
class EvenementAFO(CommonModel):
    evenement = OneToOneField(Evenement,
                              related_name='afo',
                              verbose_name=_('événement'),
                              on_delete=CASCADE)
    nom_festival = CharField(_('nom du festival'), max_length=80, blank=True)
    tournee = CharField(_('code ou titre de la tournée'),
                        max_length=60,
                        blank=True)
    cycle = CharField(_('cycle'), max_length=40, blank=True)
    code_programme = CharField(_('code du programme'),
                               max_length=60,
                               blank=True)
    titre_programme = CharField(_('titre du programme'),
                                max_length=200,
                                blank=True)
    TYPES_DE_PROGRAMMES = (
        ('LS', _('lyrique version scénique')),
        ('MC', _('musique de chambre')),
        ('LC', _('lyrique version concert')),
        ('S', _('symphonique (dont chœur/récital)')),
        ('C', _('chorégraphique')),
        ('A', _('autre')),
    )
    type_de_programme = CharField(_('typologie artistique du programme'),
                                  max_length=2,
                                  blank=True,
                                  choices=TYPES_DE_PROGRAMMES)
    PRESENTATIONS_SPECIFIQUES = (
        ('C', _('concert commenté/présenté')),
        ('P', _('concert participatif')),
        ('A', _('autre')),
    )
    presentation_specifique = CharField(_('présentation spécifique'),
                                        max_length=1,
                                        blank=True,
                                        choices=PRESENTATIONS_SPECIFIQUES)
    PUBLICS_SPECIFIQUES = (
        ('P', _('public de proximité')),
        ('E', _('public empêché (santé, handicap, justice)')),
        ('S', _('seniors')),
        ('J', _('jeunes')),
        ('JS', _('jeunes en temps scolaire')),
        ('JV', _('jeunes hors temps scolaire')),
    )
    public_specifique = CharField(_('public spécifique'),
                                  max_length=2,
                                  blank=True,
                                  choices=PUBLICS_SPECIFIQUES)
    MODALITES_DE_PRODUCTION = (
        ('P', _('participation aux frais')),
        ('A', _('autoproduction')),
        ('Ce', _('contrat de cession')),
        ('Cp', _('contrat de coproduction')),
        ('Cr', _('contrat de coréalisation')),
        ('L', _('location')),  # TODO: Pas sûr que ce soit une bonne valeur.
    )
    modalite_de_production = CharField(_('modalité de production'),
                                       max_length=2,
                                       blank=True,
                                       choices=MODALITES_DE_PRODUCTION)
    permanents = PositiveIntegerField(
        _('nombre de musiciens permanents convoqués (dont remplaçants)'),
        null=True,
        blank=True)
    remplacants = PositiveIntegerField(_('nombre de musiciens remplaçants'),
                                       null=True,
                                       blank=True)
    supplementaires = PositiveIntegerField(
        _('nombre de musiciens supplémentaires convoqués'),
        null=True,
        blank=True)
    nomenclature = TextField(_('nomenclature'), blank=True)
    exonerees = PositiveIntegerField(_('entrées exonérées'),
                                     null=True,
                                     blank=True)
    payantes = PositiveIntegerField(_('entrées payantes'),
                                    null=True,
                                    blank=True)
    scolaires = PositiveIntegerField(_('entrées scolaires'),
                                     null=True,
                                     blank=True)
    frequentation = PositiveIntegerField(_('fréquentation totale'),
                                         null=True,
                                         blank=True)
    jauge = PositiveIntegerField(_('jauge'), null=True, blank=True)

    class Meta(object):
        verbose_name = _('événement AFO')
        verbose_name_plural = _('événements AFO')

    def __str__(self):
        return force_text(self.evenement)
Ejemplo n.º 38
0
class ExtraDocument(Model):
    """Extra documents for the Income."""
    image = ImageField()
    comment = TextField()
Ejemplo n.º 39
0
 def resolve_all_reporters(self, info, **args):
     return Reporter.objects.annotate(
         full_name=Concat("first_name",
                          Value(" "),
                          "last_name",
                          output_field=TextField()))
Ejemplo n.º 40
0
class Person(BasePage):
    resource_type = "person"
    parent_page_types = ["People"]
    subpage_types = []
    template = "person.html"

    # Content fields
    nickname = CharField(max_length=250, null=True, blank=True)
    job_title = CharField(max_length=250)
    role = CharField(max_length=250, choices=ROLE_CHOICES, default="staff")
    description = RichTextField(
        "About",
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional ‘About me’ section content, supports rich text",
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )

    # Card fields
    card_title = CharField("Title", max_length=140, blank=True, default="")
    card_description = TextField("Description", max_length=400, blank=True, default="")
    card_image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
        verbose_name="Image",
    )

    # Meta
    city = CharField(max_length=250, blank=True, default="")
    country = CountryField()
    twitter = CharField(max_length=250, blank=True, default="")
    facebook = CharField(max_length=250, blank=True, default="")
    linkedin = CharField(max_length=250, blank=True, default="")
    github = CharField(max_length=250, blank=True, default="")
    email = CharField(max_length=250, blank=True, default="")
    websites = StreamField(
        StreamBlock([("website", PersonalWebsiteBlock())], max_num=3, required=False),
        null=True,
        blank=True,
        help_text="Optional links to any other personal websites",
    )
    keywords = ClusterTaggableManager(through=PersonTag, blank=True)

    # Content panels
    content_panels = [
        MultiFieldPanel(
            [
                CustomLabelFieldPanel("title", label="Full name"),
                FieldPanel("nickname"),
                FieldPanel("job_title"),
                FieldPanel("role"),
            ],
            heading="Details",
        ),
        FieldPanel("description"),
        MultiFieldPanel(
            [ImageChooserPanel("image")],
            heading="Image",
            help_text=(
                "Optional header image. If not specified a fallback will be used. "
                "This image is also shown when sharing this page via social media"
            ),
        ),
    ]

    # Card panels
    card_panels = [
        FieldPanel("card_title"),
        FieldPanel("card_description"),
        ImageChooserPanel("card_image"),
    ]

    # Meta panels
    meta_panels = [
        MultiFieldPanel(
            [FieldPanel("city"), FieldPanel("country")],
            heading="Location",
            help_text=(
                "Location fields. The country field is also filterable "
                "via the people directory page."
            ),
        ),
        MultiFieldPanel(
            [InlinePanel("topics")], heading="Topics this person specializes in"
        ),
        MultiFieldPanel(
            [
                FieldPanel("twitter"),
                FieldPanel("facebook"),
                FieldPanel("linkedin"),
                FieldPanel("github"),
                FieldPanel("email"),
            ],
            heading="Profiles",
            help_text="",
        ),
        StreamFieldPanel("websites"),
        MultiFieldPanel(
            [
                FieldPanel("seo_title"),
                FieldPanel("search_description"),
                ImageChooserPanel("social_image"),
                FieldPanel("keywords"),
            ],
            heading="SEO",
            help_text=(
                "Optional fields to override the default title and description "
                "for SEO purposes"
            ),
        ),
    ]

    # Settings panels
    settings_panels = [FieldPanel("slug")]

    # Tabs
    edit_handler = TabbedInterface(
        [
            ObjectList(content_panels, heading="Content"),
            ObjectList(card_panels, heading="Card"),
            ObjectList(meta_panels, heading="Meta"),
            ObjectList(settings_panels, heading="Settings", classname="settings"),
        ]
    )

    @property
    def display_title(self):
        """
        Return the display title for profile pages. Adds a nickname to the
        person's full name when one is provided.
        """
        return f'{self.title} aka "{self.nickname}"' if self.nickname else self.title

    @property
    def events(self):
        """
        Return upcoming events where this person is a speaker,
        ordered by start date
        """
        from ..events.models import Event

        upcoming_events = Event.published_objects.filter(
            start_date__gte=datetime.datetime.now()
        )

        speaker_events = Event.published_objects.none()

        for event in upcoming_events.all():
            # add the event to the list if the current person is a speaker
            if event.has_speaker(self):
                speaker_events = speaker_events | Event.published_objects.page(event)

        return speaker_events.order_by("start_date")

    @property
    def articles(self):
        """
        Return articles and external articles where this person is (one of) the authors,
        ordered by article date, most recent first
        """
        from ..articles.models import Article
        from ..externalcontent.models import ExternalArticle

        articles = Article.published_objects.none()
        external_articles = ExternalArticle.published_objects.none()

        all_articles = Article.published_objects.all()
        all_external_articles = ExternalArticle.published_objects.all()

        for article in all_articles:
            if article.has_author(self):
                articles = articles | Article.published_objects.page(article)

        for external_article in all_external_articles:
            if external_article.has_author(self):
                external_articles = external_articles | (
                    ExternalArticle.published_objects.page(external_article)
                )

        return sorted(
            chain(articles, external_articles), key=attrgetter("date"), reverse=True
        )

    @property
    def videos(self):
        """
        Return the most recent videos and external videos where this person is (one of)
        the speakers.
        """
        from ..videos.models import Video
        from ..externalcontent.models import ExternalVideo

        videos = Video.published_objects.none()
        external_videos = ExternalVideo.published_objects.none()

        all_videos = Video.published_objects.all()
        all_external_videos = ExternalVideo.published_objects.all()

        for video in all_videos:
            if video.has_speaker(self):
                videos = videos | Video.published_objects.page(video)

        for external_video in all_external_videos:
            if external_video.has_speaker(self):
                external_videos = external_videos | (
                    ExternalVideo.published_objects.page(external_video)
                )

        return sorted(
            chain(videos, external_videos), key=attrgetter("date"), reverse=True
        )

    @property
    def role_group(self):
        return {"slug": self.role, "title": dict(ROLE_CHOICES).get(self.role, "")}

    @property
    def country_group(self):
        return (
            {"slug": self.country.code.lower(), "title": self.country.name}
            if self.country
            else {"slug": ""}
        )
Ejemplo n.º 41
0
 def ready(self):
     CharField.register_lookup(Unaccent)
     TextField.register_lookup(Unaccent)
Ejemplo n.º 42
0
from django.apps import AppConfig