Beispiel #1
0
class HomePage(Page):
    subpage_types = ['content.ContentPage']
    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='+'
    )
    featured = StreamField(
        StreamBlock([
            ('article', PageChooserBlock(required=False, target_model=(
                'articles.Article',
                'externalcontent.ExternalArticle',
            ))),
            ('external_page', FeaturedExternalBlock()),
        ], min_num=0, max_num=4),
        null=True,
        blank=True,
    )
    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=140, 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",
        ),
        ImageChooserPanel('image'),
        StreamFieldPanel('featured'),
        MultiFieldPanel(
            [
                FieldPanel('about_title'),
                FieldPanel('about_subtitle'),
                FieldPanel('about_button_text'),
                FieldPanel('about_button_url'),
            ],
            heading="About section",
        )
    ]

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

    # Meta panels
    meta_panels = [
        MultiFieldPanel([
            FieldPanel('seo_title'),
            FieldPanel('search_description'),
            FieldPanel('keywords'),
        ], heading='SEO'),
    ]

    # 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 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')
Beispiel #2
0
class Event(Page):
    resource_type = 'event'
    parent_page_types = ['events.Events']
    subpage_types = []
    template = 'event.html'

    # Content fields
    description = TextField(
        blank=True,
        default='',
        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 = Page.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'),
                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 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:
            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
Beispiel #3
0
class FormSubmit(Model):
    user_agent = TextField("Client's user agent", null = True)
    ip_address = CharField("Client's IP address", max_length = 45, null = True)
    referer = URLField("HTTP referer", null = True)
    query_string = TextField("Query string")
    query = TextField("The 'q' parameter in the query")
Beispiel #4
0
class Person(ClusterableModel, index.Indexed):

    user = OneToOneField(User,
                         null=True,
                         blank=True,
                         on_delete=CASCADE,
                         related_name='profile')
    first_name = CharField(max_length=255)
    middle_name = CharField(max_length=255, null=True, blank=True)
    last_name = CharField(max_length=255)
    bio = RichTextField(blank=True)

    photo = ForeignKey('wagtailimages.Image',
                       null=True,
                       blank=True,
                       on_delete=SET_NULL,
                       related_name='+')

    position = CharField(max_length=140, blank=True)
    term = CharField(blank=True, max_length=9, help_text="Format:YYYY-YYYY")
    linked_in = URLField(blank=True)
    blog_url = URLField(blank=True)
    osf_profile = URLField(blank=True)
    google_plus = URLField(blank=True)
    github = URLField(blank=True)
    twitter = URLField(blank=True)
    phone_number = CharField(max_length=12,
                             blank=True,
                             help_text="Format:XXX-XXX-XXXX")
    email_address = EmailField(blank=True)

    favorite_food = CharField(max_length=140, blank=True)

    tags = TaggableManager(through='common.PersonTag', blank=True)

    search_fields = [
        index.SearchField('first_name', partial_match=True),
        index.SearchField('last_name', partial_match=True),
        index.SearchField('middle_name', partial_match=True),
    ]

    panels = [
        MultiFieldPanel([
            FieldPanel('user'),
            FieldPanel('first_name'),
            FieldPanel('middle_name'),
            FieldPanel('last_name'),
            FieldPanel('bio'),
            FieldPanel('tags'),
            FieldPanel('position'),
            FieldPanel('term'),
            FieldPanel('linked_in'),
            FieldPanel('blog_url'),
            FieldPanel('osf_profile'),
            FieldPanel('google_plus'),
            FieldPanel('github'),
            FieldPanel('twitter'),
            FieldPanel('phone_number'),
            FieldPanel('email_address'),
            FieldPanel('favorite_food'),
        ],
                        heading='Basic Information'),
        ImageChooserPanel('photo'),
    ]

    class Meta:
        verbose_name_plural = "People"
        ordering = ['last_name']

    def __str__(self):
        return '{self.last_name}, {self.first_name}'.format(self=self)
Beispiel #5
0
class Source(AutoriteModel):
    parent = ForeignKey(
        'self',
        related_name='children',
        verbose_name=_('parent'),
        null=True,
        blank=True,
        on_delete=CASCADE,
        help_text=_(
            'À remplir par exemple si la source est une page d’un recueil '
            'déjà existant ou un tome d’une série.'),
    )
    position = PositiveIntegerField(
        _('position'),
        null=True,
        blank=True,
        help_text=_('Position au sein de son parent.'))
    est_promu = BooleanField(_('est dans la bibliothèque'), default=False)

    type = ForeignKey('TypeDeSource',
                      related_name='sources',
                      help_text=ex(_('compte rendu')),
                      verbose_name=_('type'),
                      on_delete=PROTECT)
    titre = CharField(_('titre'),
                      max_length=200,
                      blank=True,
                      db_index=True,
                      help_text=ex(_('Journal de Rouen')))
    legende = CharField(_('légende'),
                        max_length=600,
                        blank=True,
                        help_text=_('Recommandée pour les images.'))

    ancrage = AncrageSpatioTemporel(has_heure=False, has_lieu=False)
    numero = NumberCharField(
        _('numéro'),
        max_length=50,
        blank=True,
        db_index=True,
        help_text=_('Sans « № ». Exemple : « 52 »'),
    )
    folio = CharField(_('folio'),
                      max_length=15,
                      blank=True,
                      help_text=_('Sans « f. ». Exemple : « 3 ».'))
    page = CharField(_('page'),
                     max_length=15,
                     blank=True,
                     db_index=True,
                     help_text=_('Sans « p. ». Exemple : « 3 »'))
    lieu_conservation = CharField(_('lieu de conservation'),
                                  max_length=75,
                                  blank=True,
                                  db_index=True)
    cote = CharField(_('cote'), max_length=60, blank=True, db_index=True)
    url = URLField(_('URL'),
                   blank=True,
                   help_text=_('Uniquement un permalien extérieur à Dezède.'))

    transcription = HTMLField(
        _('transcription'),
        blank=True,
        help_text=_('Recopier la source ou un extrait en suivant les règles '
                    'définies dans '  # FIXME: Don’t hardcode the URL.
                    '<a href="/examens/source">le didacticiel.</a>'),
    )

    fichier = FileField(_('fichier'), upload_to='files/', blank=True)
    TYPES = (
        (FileAnalyzer.OTHER, _('autre')),
        (FileAnalyzer.IMAGE, _('image')),
        (FileAnalyzer.AUDIO, _('audio')),
        (FileAnalyzer.VIDEO, _('vidéo')),
    )
    type_fichier = PositiveSmallIntegerField(
        choices=TYPES,
        null=True,
        blank=True,
        editable=False,
        db_index=True,
    )
    telechargement_autorise = BooleanField(
        _('téléchargement autorisé'),
        default=True,
    )

    evenements = ManyToManyField('Evenement',
                                 through='SourceEvenement',
                                 related_name='sources',
                                 verbose_name=_('événements'))
    oeuvres = ManyToManyField('Oeuvre',
                              through='SourceOeuvre',
                              related_name='sources',
                              verbose_name=_('œuvres'))
    individus = ManyToManyField('Individu',
                                through='SourceIndividu',
                                related_name='sources',
                                verbose_name=_('individus'))
    ensembles = ManyToManyField('Ensemble',
                                through='SourceEnsemble',
                                related_name='sources',
                                verbose_name=_('ensembles'))
    lieux = ManyToManyField('Lieu',
                            through='SourceLieu',
                            related_name='sources',
                            verbose_name=_('lieux'))
    parties = ManyToManyField('Partie',
                              through='SourcePartie',
                              related_name='sources',
                              verbose_name=_('sources'))

    #
    # Dossier
    #

    # Métadonnées
    editeurs_scientifiques = ManyToManyField(
        'accounts.HierarchicUser',
        related_name='sources_editees',
        verbose_name=_('éditeurs scientifiques'),
        blank=True,
    )
    date_publication = DateField(_('date de publication'),
                                 default=datetime.datetime.now)
    publications = TextField(_('publication(s) associée(s)'), blank=True)
    developpements = TextField(_('développements envisagés'), blank=True)

    # Article
    presentation = TextField(_('présentation'), blank=True)
    contexte = TextField(_('contexte historique'), blank=True)
    sources_et_protocole = TextField(_('sources et protocole'), blank=True)
    bibliographie = TextField(_('bibliographie indicative'), blank=True)

    objects = SourceManager()

    class Meta:
        verbose_name = _('source')
        verbose_name_plural = _('sources')
        ordering = (
            'date',
            'titre',
            'numero',
            'parent__date',
            'parent__titre',
            'parent__numero',
            'position',
            'page',
            'lieu_conservation',
            'cote',
        )
        permissions = (('can_change_status', _('Peut changer l’état')), )

    def __str__(self):
        return strip_tags(self.html(False))

    def has_presentation_tab(self):
        def iterator():
            yield self.editeurs_scientifiques.exists()
            yield self.publications
            yield self.developpements
            yield self.presentation
            yield self.contexte
            yield self.sources_et_protocole
            yield self.bibliographie

        return any(iterator())

    def has_index_tab(self):
        def iterator():
            yield self.parent
            yield self.auteurs_html()
            yield self.nested_individus()
            yield self.nested_oeuvres()
            yield self.nested_parties()
            yield self.nested_evenements()
            yield self.nested_ensembles()
            yield self.notes_publiques

        return any(iterator())

    @cached_property
    def specific(self):
        if self.type_fichier == FileAnalyzer.AUDIO:
            return Audio.objects.get(pk=self.pk)
        if self.type_fichier == FileAnalyzer.VIDEO:
            return Video.objects.get(pk=self.pk)
        return self

    @permalink
    def get_absolute_url(self):
        return 'source_permanent_detail', (self.pk, )

    @permalink
    def get_change_url(self):
        meta = self.specific._meta
        return f'admin:{meta.app_label}_{meta.model_name}_change', (self.pk, )

    def permalien(self):
        return self.get_absolute_url()

    def link(self):
        return self.html()

    link.short_description = _('Lien')
    link.allow_tags = True

    def auteurs_html(self, tags=True):
        return self.auteurs.html(tags)

    def no(self):
        return ugettext('n° %s') % self.numero

    def f(self):
        return ugettext('f. %s') % self.folio

    def p(self):
        return ugettext('p. %s') % self.page

    def html(self, tags=True, pretty_title=False, link=True):
        url = None if not tags else self.get_absolute_url()
        conservation = hlp(self.lieu_conservation,
                           ugettext('Lieu de conservation'), tags)
        if self.ancrage.date or self.ancrage.date_approx:
            ancrage = hlp(self.ancrage.html(tags, caps=False),
                          ugettext('date'))
        else:
            ancrage = None
        if self.cote:
            conservation += f", {hlp(self.cote, 'cote', tags)}"
        if self.titre:
            l = [cite(self.titre, tags)]
            if self.numero:
                l.append(self.no())
            if ancrage is not None:
                l.append(ancrage)
            if self.lieu_conservation:
                l[-1] += f' ({conservation})'
        else:
            l = [conservation]
            if ancrage is not None:
                l.append(ancrage)
        if self.folio:
            l.append(hlp(self.f(), ugettext('folio'), tags))
        if self.page:
            l.append(hlp(self.p(), ugettext('page'), tags))
        if self.parent is not None:
            l.insert(
                0,
                self.parent.html(tags=tags,
                                 pretty_title=pretty_title,
                                 link=pretty_title))
        l = (l[0], small(str_list(l[1:]), tags=tags)) if pretty_title else l
        out = str_list(l)
        if link:
            return mark_safe(href(url, out, tags))
        return out

    html.short_description = _('rendu HTML')
    html.allow_tags = True

    def pretty_title(self):
        return self.html(pretty_title=True, link=False)

    def has_events(self):
        if hasattr(self, '_has_events'):
            return self._has_events
        return self.evenements.exists()

    has_events.short_description = _('événements')
    has_events.boolean = True
    has_events.admin_order_field = 'evenements'

    def has_program(self):
        if hasattr(self, '_has_program'):
            return self._has_program
        return self.evenements.with_program().exists()

    has_program.short_description = _('programme')
    has_program.boolean = True

    def is_other(self):
        return self.type_fichier == FileAnalyzer.OTHER

    def is_pdf(self):
        return self.is_other() and self.fichier.name.endswith('.pdf')

    def is_image(self):
        return self.type_fichier == FileAnalyzer.IMAGE

    def is_audio(self):
        return self.type_fichier == FileAnalyzer.AUDIO

    def is_video(self):
        return self.type_fichier == FileAnalyzer.VIDEO

    def has_children_images(self):
        return self.children.filter(type_fichier=FileAnalyzer.IMAGE).exists()

    def has_images(self):
        return (self.type_fichier == FileAnalyzer.IMAGE
                or self.has_children_images())

    def has_fichiers(self):
        return (self.is_other() or self.is_audio() or self.is_video()
                or self.has_images())

    def images_iterator(self):
        if self.is_image():
            yield self
        for child in Source.objects.filter(
                Q(parent=self) | Q(parent__parent=self),
                type_fichier=FileAnalyzer.IMAGE,
        ).order_by('position', 'page'):
            yield child

    @cached_property
    def images(self):
        return list(self.images_iterator())

    @cached_property
    def preview_image(self):
        return next(self.images_iterator())

    @cached_property
    def is_collection(self):
        return Source.objects.filter(parent__parent=self).exists()

    def is_empty(self):
        return not (self.transcription or self.url or self.has_fichiers())

    DATA_TYPES = ('video', 'audio', 'image', 'other', 'text', 'link')
    VIDEO, AUDIO, IMAGE, OTHER, TEXT, LINK = DATA_TYPES

    @property
    def data_types(self):
        data_types = []
        if self.is_video():
            data_types.append(self.VIDEO)
        if self.is_audio():
            data_types.append(self.AUDIO)
        if self.has_images():
            data_types.append(self.IMAGE)
        if self.is_other():
            data_types.append(self.OTHER)
        if self.transcription:
            data_types.append(self.TEXT)
        if self.url:
            data_types.append(self.LINK)
        return data_types

    ICONS = {
        VIDEO: '<i class="fa fa-fw fa-video-camera"></i>',
        AUDIO: '<i class="fa fa-fw fa-volume-up"></i>',
        IMAGE: '<i class="fa fa-fw fa-photo"></i>',
        OTHER: '<i class="fa fa-fw fa-paperclip"></i>',
        TEXT: '<i class="fa fa-fw fa-file-text-o"></i>',
        LINK: '<i class="fa fa-fw fa-external-link"></i>',
    }

    DATA_TYPES_WITH_ICONS = (
        (VIDEO, _(f'{ICONS[VIDEO]} Vidéo')),
        (AUDIO, _(f'{ICONS[AUDIO]} Audio')),
        (IMAGE, _(f'{ICONS[IMAGE]} Image')),
        (OTHER, _(f'{ICONS[OTHER]} Autre')),
        (TEXT, _(f'{ICONS[TEXT]} Texte')),
        (LINK, _(f'{ICONS[LINK]} Lien')),
    )

    @property
    def icons(self):
        return ''.join(
            [self.ICONS[data_type] for data_type in self.data_types])

    def update_media_info(self):
        if self.fichier:
            file_analyzer = FileAnalyzer(self, 'fichier')
            self.type_fichier = file_analyzer.type
        else:
            self.type_fichier = None

    def clean(self):
        super().clean()
        if not getattr(self, 'updated_media_info', False):
            self.update_media_info()
            self.updated_media_info = True

    @cached_property
    def first_page(self):
        return self.children.order_by('position').first()

    @cached_property
    def prev_page(self):
        if self.parent is not None:
            return self.parent.children.exclude(pk=self.pk).filter(
                position__lte=self.position, ).order_by('-position').first()

    @cached_property
    def next_page(self):
        if self.parent is not None:
            return self.parent.children.exclude(pk=self.pk).filter(
                position__gte=self.position, ).order_by('position').first()

    @property
    def filename(self):
        return Path(self.fichier.path).name

    @cached_property
    def linked_individus(self):
        return self.individus.distinct()

    @cached_property
    def linked_evenements(self):
        return self.evenements.distinct()

    @cached_property
    def linked_oeuvres(self):
        return self.oeuvres.distinct()

    @cached_property
    def linked_ensembles(self):
        return self.ensembles.distinct()

    @cached_property
    def linked_lieux(self):
        return self.lieux.distinct()

    @cached_property
    def linked_parties(self):
        return self.parties.distinct()

    def get_linked_objects(self):
        return [
            *self.auteurs.all(),
            *self.linked_individus,
            *self.linked_evenements,
            *self.linked_oeuvres,
            *self.linked_ensembles,
            *self.linked_lieux,
            *self.linked_parties,
        ]

    def get_linked_objects_json(self):
        return json.dumps([{
            'url': obj.get_absolute_url(),
            'label': str(obj),
            'model': obj.class_name().lower(),
        } for obj in self.get_linked_objects()])

    def nested_evenements(self):
        return apps.get_model('libretto.Evenement').objects.filter(
            sources__in=self.children.all()
            | Source.objects.filter(pk=self.pk)).distinct()

    def nested_oeuvres(self):
        return apps.get_model('libretto.Oeuvre').objects.filter(
            sources__in=self.children.all()
            | Source.objects.filter(pk=self.pk)).distinct()

    def nested_individus(self):
        return apps.get_model('libretto.Individu').objects.filter(
            sources__in=self.children.all()
            | Source.objects.filter(pk=self.pk)).distinct()

    def nested_ensembles(self):
        return apps.get_model('libretto.Ensemble').objects.filter(
            sources__in=self.children.all()
            | Source.objects.filter(pk=self.pk)).distinct()

    def nested_lieux(self):
        return apps.get_model('libretto.Lieu').objects.filter(
            sources__in=self.children.all()
            | Source.objects.filter(pk=self.pk)).distinct()

    def nested_parties(self):
        return apps.get_model('libretto.Partie').objects.filter(
            sources__in=self.children.all()
            | Source.objects.filter(pk=self.pk)).distinct()

    @property
    def small_thumbnail(self):
        if self.is_image():
            thumbnailer = get_thumbnailer(self.fichier)
            return thumbnailer.get_thumbnail(aliases.get('small')).url

    @property
    def medium_thumbnail(self):
        if self.is_image():
            thumbnailer = get_thumbnailer(self.fichier)
            return thumbnailer.get_thumbnail(aliases.get('medium')).url

    @staticmethod
    def autocomplete_search_fields():
        return (
            'type__nom__unaccent__icontains',
            'titre__unaccent__icontains',
            'date__icontains',
            'date_approx__unaccent__icontains',
            'numero__unaccent__icontains',
            'lieu_conservation__unaccent__icontains',
            'cote__unaccent__icontains',
        )
Beispiel #6
0
def details_url_annotate(queryset,
                         app_path=None,
                         model_path=None,
                         param_name=None,
                         param_lookup_name=None):
    """
    annotate each row in a `queryset` with an admin link to related records

    For example, we have a hosts and host events and host events linked via a
    :class:`Django Foreign Key
    <django.db.models.ForeignKey>` field. This function will annotate each row in
    the hosts `queryset` with the absolute `Django admin URL` to the related
    host events like below::

        http://10.2.50.35:8080/admin/citrus_borg/winlogevent/?source_host__host_name=bccss-t450s-02

    :arg queryset: the initial :class:`Django queryset
        <django.db.models.query.QuerySet>`

    :arg str app_path: the `app_label` for the model with the details.
        If ``None``, the `app_label` is picked from the `queryset` using the
        `Model _meta API
        <https://docs.djangoproject.com/en/2.2/ref/models/meta/#module-django.db.models.options>`_.
        This is only useful if the master and the details models are defined in the
        same `Django application`.

    :arg str model_path: the `model_name` property of the `Django model` with the
        details. If ``None``, it will be picked from the `queryset` using the
        `Model _meta API`. This, however, is o very little use, since there are
        very few realistic data models where the master and the details are in
        the same `Djanog model`.

    :arg str param_name: `Django lookup` key_name__field_name used to build the
        `param` part of the `URL`. If one considers the example above, this
        argument is 'source_host__host_name' which means that the events
        (the details) model has a foreign key named 'source_host' pointing to
        the hosts (master) model and the lookup will be applied against a
        field named 'host_name' in the later model.

    :arg str param_lookup_name: the name of the field that contains the `value`
        part of the `URL`. If one considers the example above, the value used
        in the filter is picked from the field containing the host_name.
    """
    if not isinstance(queryset, QuerySet):
        raise TypeError('bad type %s for object %s' %
                        (type(queryset), queryset))

    if param_name is None:
        raise ValueError(
            'cannot build URL parameters without a parameter name')

    if param_lookup_name is None:
        raise ValueError(
            'cannot build URL parameters without a parameter value')

    obj_sample = queryset.model._meta

    if app_path is None:
        app_path = obj_sample.app_label

    if model_path is None:
        model_path = obj_sample.model_name

    try:
        return queryset.annotate(
            details_url=Concat(Value(settings.SERVER_PROTO),
                               Value('://'),
                               Value(socket.getfqdn()),
                               Value(':'),
                               Value(settings.SERVER_PORT),
                               Value('/admin/'),
                               Value(app_path),
                               Value('/'),
                               Value(model_path),
                               Value('/?'),
                               Value(param_name),
                               Value('='),
                               F(param_lookup_name),
                               output_field=URLField()))
    except Exception as error:
        raise error
Beispiel #7
0
class Organization(BaseModel):
    """ Fields:
    name -- Unique organization name
    url -- Internet site URL
    email -- list of emails
    phone -- list of phones

    """
    class Meta(BaseModel.Meta):
        ordering = ('name', )
        unique_together = tuple(
            ('name_%s' % lang[0], 'monitoring') for lang in settings.LANGUAGES)
        verbose_name = pgettext_lazy(u'change organization in admin',
                                     u'Organization')
        verbose_name_plural = _('Organizations')

    name = CharField(max_length=255, verbose_name=_('name'))
    url = URLField(max_length=255,
                   null=True,
                   blank=True,
                   verbose_name=_('Website'))
    email = EmailsField(null=True, blank=True, verbose_name=_('email'))
    phone = PhonesField(null=True, blank=True, verbose_name=_('phone'))
    monitoring = ForeignKey("Monitoring",
                            verbose_name=_('monitoring'),
                            editable=False)

    inv_code = CharField(verbose_name=_("Invitation code"),
                         blank=True,
                         max_length=6,
                         unique=True,
                         editable=False)
    inv_status = CharField(max_length=3,
                           choices=INV_STATUS,
                           default='NTS',
                           verbose_name=_('Invitation status'),
                           editable=False)

    recommendations_hidden = BooleanField(
        verbose_name=_("Recommendations hidden"), default=False)

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.pk and not self.inv_code:
            self.inv_code = generate_inv_code(6)
        super(Organization, self).save(*args, **kwargs)

    def validate_unique(self, exclude=None):
        """
        Prevent "monitoring" field from being excluded in validation checks.
        This is workaround for Django bug 13091 https://code.djangoproject.com/ticket/13091

        This workaround will force modelform to validate unique_together constraints involving
        "monitoring" field on the model, even if "monitoring" field is absent in the form.
        - Failing to do that will raise IntegrityError on instance saving.

        """
        if 'monitoring' in exclude:
            exclude.remove('monitoring')
        super(Organization, self).validate_unique(exclude)

    def clean(self):
        """
        Replace empty strings with None for all modeltranslation fields to store NULL in database.
        This will allow multiple orgs with empty modeltranslation fields to pass unique checks during form validation.
        """
        from exmo2010.translation import OrganizationTranslationOptions
        for field in OrganizationTranslationOptions.fields:
            for lang in settings.LANGUAGES:
                if not getattr(self, '{}_{}'.format(field, lang[0])):
                    setattr(self, '{}_{}'.format(field, lang[0]), None)

    def email_iter(self):
        if not self.email:
            return

        for email in self.email.replace(' ', '').split(','):
            if email:
                yield email
Beispiel #8
0
class Study(Model):

    EEA = 'eea'
    OTHER = 'other'
    REQUESTED_BY_CHOICES = (
        (EEA, 'EEA'),
        (OTHER, 'Other'),
    )

    YES = 1
    NO = 0
    YES_NO_CHOICES = (
        ('', '----'),
        (YES, 'Yes'),
        (NO, 'No'),
    )

    POLICY = 'policy'
    NON_POLICY = 'non_policy'
    PURPOSE_CHOICES = (
        (POLICY, 'Support to policy'),
        (NON_POLICY, 'Non-policy (research, civil initiative, NGOs...'),
    )

    ACTIVITY = 'activity'
    EVALUATION = 'evaluation'
    TYPE_CHOICES = (
        (ACTIVITY, 'Forward looking activity'),
        (EVALUATION, 'Evaluation'),
    )

    BLOSSOM_CHOICES = (
        (YES, 'BLOSSOM study'),
        (NO, 'other study'),
    )

    draft = BooleanField(default=True)

    created_on = DateTimeField(auto_now_add=True)

    last_updated = DateTimeField(auto_now_add=True, auto_now=True)

    user_id = CharField(max_length=64, blank=True)

    title = CharField('title in English', max_length=255)

    languages = ManyToManyField('Language',
                                verbose_name='language of the study',
                                through='StudyLanguage')

    url = URLField(blank=True)

    study_type = CharField(
        'I want to add a new',
        choices=TYPE_CHOICES,
        max_length=128,
        null=True,
    )

    blossom = IntegerField(
        'Approach to evaluation',
        choices=BLOSSOM_CHOICES,
        default=NO,
    )

    requested_by = CharField('who requested the study?',
                             max_length=64,
                             choices=REQUESTED_BY_CHOICES,
                             blank=True)

    start_date = DateField('start date', null=True, blank=True)

    end_date = DateField('end date')

    lead_author = TextField('lead author')

    other = TextField('other organisations/authors or contact persons',
                      blank=True)

    purpose_and_target = CharField(
        'purpose and target audience',
        max_length=128,
        choices=PURPOSE_CHOICES,
        blank=True,
    )

    additional_information = TextField('additional information', blank=True)

    phase_of_policy = ForeignKey('PhasesOfPolicy',
                                 verbose_name='phases of policy cycle',
                                 null=True,
                                 blank=True)

    additional_information_phase = TextField(
        ('additional information about the application'), blank=True)

    foresight_approaches = ManyToManyField(
        'ForesightApproaches', verbose_name='foresight approaches used')

    additional_information_foresight = TextField('additional information',
                                                 blank=True)

    stakeholder_participation = BooleanField('stakeholder participation',
                                             default=False)

    additional_information_stakeholder = TextField(
        'additional information about stakeholder involvement', blank=True)

    environmental_themes = ManyToManyField('common.EnvironmentalTheme',
                                           verbose_name='topics',
                                           blank=True)

    geographical_scope = ForeignKey('common.GeographicalScope',
                                    verbose_name='geographical scope',
                                    null=True,
                                    blank=True)

    countries = ManyToManyField('common.Country',
                                verbose_name='countries',
                                blank=True)

    def __unicode__(self):
        return self.title
Beispiel #9
0
class AppRelease(TranslatableModel):
    version = CharField(max_length=256,
                        verbose_name=_('Version'),
                        help_text=_('Version follows Semantic Versioning'))
    app = ForeignKey('App',
                     on_delete=CASCADE,
                     verbose_name=_('App'),
                     related_name='releases')
    # dependencies
    php_extensions = ManyToManyField(
        'PhpExtension',
        blank=True,
        through='PhpExtensionDependency',
        verbose_name=_('PHP extension dependency'))
    databases = ManyToManyField('Database',
                                blank=True,
                                through='DatabaseDependency',
                                verbose_name=_('Database dependency'))
    licenses = ManyToManyField('License', verbose_name=_('License'))
    shell_commands = ManyToManyField(
        'ShellCommand', blank=True, verbose_name=_('Shell command dependency'))
    php_version_spec = CharField(max_length=256,
                                 verbose_name=_('PHP version requirement'))
    platform_version_spec = CharField(
        max_length=256, verbose_name=_('Platform version requirement'))
    raw_php_version_spec = CharField(
        max_length=256, verbose_name=_('PHP version requirement (raw)'))
    raw_platform_version_spec = CharField(
        max_length=256, verbose_name=_('Platform version requirement (raw)'))
    min_int_size = IntegerField(blank=True,
                                default=32,
                                verbose_name=_('Minimum Integer bits'),
                                help_text=_('e.g. 32 for 32bit Integers'))
    download = URLField(max_length=256,
                        blank=True,
                        verbose_name=_('Archive download URL'))
    created = DateTimeField(auto_now_add=True,
                            editable=False,
                            verbose_name=_('Created at'))
    last_modified = DateTimeField(auto_now=True,
                                  editable=False,
                                  db_index=True,
                                  verbose_name=_('Updated at'))
    signature = TextField(
        verbose_name=_('Signature'),
        help_text=_('A signature using the app\'s certificate'))
    signature_digest = CharField(max_length=256,
                                 verbose_name=_('Signature hashing algorithm'))
    translations = TranslatedFields(changelog=TextField(
        verbose_name=_('Changelog'),
        help_text=_('The release changelog. Can contain Markdown'),
        default=''))
    is_nightly = BooleanField(verbose_name=_('Nightly'), default=False)

    class Meta:
        verbose_name = _('App release')
        verbose_name_plural = _('App releases')
        unique_together = (('app', 'version', 'is_nightly'), )
        ordering = ['-version']

    def can_update(self, user: User) -> bool:
        return self.app.owner == user or user in self.app.co_maintainers.all()

    def can_delete(self, user: User) -> bool:
        return self.can_update(user)

    def __str__(self) -> str:
        return '%s %s' % (self.app, self.version)

    def is_compatible(self, platform_version, inclusive=False):
        """Checks if a release is compatible with a platform version

        :param platform_version: the platform version, not required to be
                                 semver compatible
        :param inclusive: if True the check will also return True if an app
                          requires 9.0.1 and the given platform version is 9.0
        :return: True if compatible, otherwise false
        """

        min_version = Version(pad_min_version(platform_version))
        spec = Spec(self.platform_version_spec)
        if inclusive:
            max_version = Version(pad_max_inc_version(platform_version))
            return (min_version in spec or max_version in spec)
        else:
            return min_version in spec

    @property
    def is_unstable(self):
        return self.is_nightly or '-' in self.version
class Test(Model):

    id = UUIDField(
        primary_key=True,
        default=uuid4,
        editable=False,
    )

    label = CharField(
        verbose_name=_("label"),
        max_length=32,
        blank=False,
        db_index=True,
        unique=True,
    )

    category = ForeignKey(
        verbose_name=_("category"),
        related_name="test_set",
        to=Category,
        null=True,
        blank=True,
        db_index=True,
        on_delete=PROTECT,
    )

    theme_set = ManyToManyField(
        verbose_name=_("theme_set"),
        related_name="test_set",
        to=Theme,
        blank=True,
    )

    category2 = ForeignKey(
        verbose_name=_("category 2"),
        related_name="test2_set",
        to=Category,
        null=True,
        blank=True,
        db_index=True,
        on_delete=CASCADE,
    )

    theme_set2 = ManyToManyField(
        verbose_name=_("theme_set 2"),
        related_name="test2_set",
        to=Theme,
        blank=True,
    )

    category3 = ForeignKey(
        verbose_name=_("category 3"),
        related_name="test3_set",
        to=Category,
        null=True,
        blank=True,
        db_index=True,
        on_delete=CASCADE,
    )

    theme_set3 = ManyToManyField(
        verbose_name=_("theme_set 3"),
        related_name="test3_set",
        to=Theme,
        blank=True,
    )

    category4 = ForeignKey(
        verbose_name=_("category 4"),
        related_name="test4_set",
        to=Category,
        null=True,
        blank=True,
        db_index=True,
        on_delete=CASCADE,
    )

    theme_set4 = ManyToManyField(
        verbose_name=_("theme_set 4"),
        related_name="test4_set",
        to=Theme,
        blank=True,
    )

    category5 = ForeignKey(
        verbose_name=_("category 5"),
        related_name="test5_set",
        to=Category,
        null=True,
        blank=True,
        db_index=True,
        on_delete=CASCADE,
    )

    theme_set5 = ManyToManyField(
        verbose_name=_("theme_set 5"),
        related_name="test5_set",
        to=Theme,
        blank=True,
    )

    category6 = ForeignKey(
        verbose_name=_("category 6"),
        related_name="test6_set",
        to=Category,
        null=True,
        blank=True,
        db_index=True,
        on_delete=CASCADE,
    )

    theme_set6 = ManyToManyField(
        verbose_name=_("theme_set 6"),
        related_name="test6_set",
        to=Theme,
        blank=True,
    )

    tag_set = ManyToManyField(
        verbose_name=_("theme_set"),
        related_name="test_set",
        to=Tag,
        through="Mapping",
        blank=True,
    )

    number = PositiveSmallIntegerField(
        verbose_name=_("number"),
        unique=True,
    )

    percent = DecimalField(
        verbose_name=_("percent"),
        max_digits=5,
        decimal_places=2,
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True,
    )

    progress = FloatField(
        verbose_name=_("progress"),
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True,
    )

    grade = IntegerField(
        verbose_name=_("grade"),
        validators=[MinValueValidator(-10),
                    MaxValueValidator(10)],
        blank=True,
        null=True,
    )

    slug = SlugField(
        unique=True,
        max_length=32,
        editable=True,
        db_index=True,
    )

    owner = EmailField(
        verbose_name=_("owner"),
        blank=True,
        null=True,
    )

    url = URLField(
        verbose_name=_("url"),
        blank=True,
        null=True,
    )

    key = UUIDField(default=uuid4, )

    description = TextField(verbose_name=_("description"), )

    active = BooleanField(verbose_name=_("active"), )

    highlight = NullBooleanField(verbose_name=_("highlight"), )

    creation_date = DateField(
        verbose_name=_("creation date"),
        auto_now_add=True,
    )

    last_modification_date = DateField(
        verbose_name=_("last modification date"),
        auto_now=True,
    )

    random_date = DateField(
        verbose_name=_("random date"),
        blank=True,
        null=True,
    )

    creation_datetime = DateTimeField(
        verbose_name=_("creation datetime"),
        auto_now_add=True,
    )

    last_modification_datetime = DateTimeField(
        verbose_name=_("last modification datetime"),
        auto_now=True,
    )

    random_datetime = DateTimeField(
        verbose_name=_("random datetime"),
        blank=True,
        null=True,
    )

    duration = DurationField(
        verbose_name=_("duration"),
        blank=True,
        null=True,
    )

    creation_time = TimeField(
        verbose_name=_("creation time"),
        auto_now_add=True,
    )

    last_modification_time = TimeField(
        verbose_name=_("last modification time"),
        auto_now=True,
    )

    random_time = TimeField(
        verbose_name=_("random time"),
        blank=True,
        null=True,
    )

    ip = GenericIPAddressField(
        verbose_name=_("IP v4 ou 6"),
        protocol="both",
        blank=True,
        null=True,
    )

    ipv4 = GenericIPAddressField(
        verbose_name=_("IP v4 as is"),
        protocol="IPv4",
        blank=True,
        null=True,
    )

    ipv6_forced = GenericIPAddressField(
        verbose_name=_("IP v6 (ipv4 will be converted)"),
        protocol="both",
        unpack_ipv4=True,
        blank=True,
        null=True,
    )

    ipv6 = GenericIPAddressField(
        verbose_name=_("IP v6"),
        protocol="IPv6",
        blank=True,
        null=True,
    )

    raw_data = BinaryField(
        verbose_name=_("raw data"),
        max_length=127,
        editable=True,
        blank=True,
        null=True,
    )

    def compute_upload_path(current_object, sub_path, filename):
        """Describe the image storage path"""
        today = now()
        return str(
            Path.joinpath(*list(
                map(
                    Path,
                    (
                        current_object._meta.app_label,  # pylint: disable=protected-access
                        current_object._meta.model_name,  # pylint: disable=protected-access
                        sub_path,
                        str(today.year),
                        str(today.month),
                        str(uuid4()) + Path(filename).suffix)))))

    file = FileField(
        verbose_name=_("file"),
        max_length=256,
        upload_to=partial(compute_upload_path, subpath="file"),
        null=True,
        blank=True,
    )

    image = ImageField(
        verbose_name=_("image"),
        max_length=256,
        upload_to=partial(compute_upload_path, subpath="image"),
        null=True,
        blank=True,
    )

    path = FilePathField(
        verbose_name=_("path"),
        path=settings.STATIC_PATH,
    )

    def __str__(self):
        """Return a string that represent the current object to an end user."""
        return self.label

    class Meta:  # pylint: disable=too-few-public-methods
        """Test Meta class"""

        verbose_name = _("test")
        verbose_name_plural = _("tests")
        ordering = ("number", )
Beispiel #11
0
class Game(Model):
    """game model"""

    bgg_id = PositiveIntegerField(primary_key=True)
    name = CharField(max_length=255, db_index=True)
    alt_name = JSONField(default=list)
    year = SmallIntegerField(blank=True, null=True, db_index=True)
    description = TextField(blank=True, null=True)

    designer = ManyToManyField("Person",
                               blank=True,
                               related_name="designer_of")
    artist = ManyToManyField("Person", blank=True, related_name="artist_of")
    # publisher = ListField(CharField(), blank=True)

    url = URLField(blank=True, null=True)
    image_url = JSONField(default=list)
    video_url = JSONField(default=list)
    external_link = JSONField(default=list)
    # list_price = CharField(max_length=100, blank=True, null=True)

    min_players = PositiveSmallIntegerField(blank=True,
                                            null=True,
                                            db_index=True)
    max_players = PositiveSmallIntegerField(blank=True,
                                            null=True,
                                            db_index=True)
    min_players_rec = PositiveSmallIntegerField(blank=True,
                                                null=True,
                                                db_index=True)
    max_players_rec = PositiveSmallIntegerField(blank=True,
                                                null=True,
                                                db_index=True)
    min_players_best = PositiveSmallIntegerField(blank=True,
                                                 null=True,
                                                 db_index=True)
    max_players_best = PositiveSmallIntegerField(blank=True,
                                                 null=True,
                                                 db_index=True)
    min_age = PositiveSmallIntegerField(blank=True, null=True, db_index=True)
    max_age = PositiveSmallIntegerField(blank=True, null=True, db_index=True)
    min_age_rec = FloatField(blank=True, null=True, db_index=True)
    max_age_rec = FloatField(blank=True, null=True, db_index=True)
    min_time = PositiveSmallIntegerField(blank=True, null=True, db_index=True)
    max_time = PositiveSmallIntegerField(blank=True, null=True, db_index=True)

    game_type = ManyToManyField("GameType", blank=True, related_name="games")
    category = ManyToManyField("Category", blank=True, related_name="games")
    mechanic = ManyToManyField("Mechanic", blank=True, related_name="games")
    cooperative = BooleanField(default=False, db_index=True)
    compilation = BooleanField(default=False, db_index=True)
    compilation_of = ManyToManyField("self",
                                     symmetrical=False,
                                     blank=True,
                                     related_name="contained_in")
    # family = ListField(CharField(), blank=True)
    # expansion = ListField(CharField(), blank=True)
    implements = ManyToManyField("self",
                                 symmetrical=False,
                                 blank=True,
                                 related_name="implemented_by")
    integrates_with = ManyToManyField("self", symmetrical=True, blank=True)

    bgg_rank = PositiveIntegerField(blank=True, null=True, db_index=True)
    num_votes = PositiveIntegerField(default=0, db_index=True)
    avg_rating = FloatField(blank=True, null=True, db_index=True)
    stddev_rating = FloatField(blank=True, null=True, db_index=True)
    bayes_rating = FloatField(blank=True, null=True, db_index=True)

    rec_rank = PositiveIntegerField(blank=True, null=True, db_index=True)
    rec_rating = FloatField(blank=True, null=True, db_index=True)
    rec_stars = FloatField(blank=True, null=True, db_index=True)

    complexity = FloatField(blank=True, null=True, db_index=True)
    language_dependency = FloatField(blank=True, null=True, db_index=True)
    kennerspiel_score = FloatField(blank=True, null=True, db_index=True)

    freebase_id = JSONField(default=list)
    wikidata_id = JSONField(default=list)
    wikipedia_id = JSONField(default=list)
    dbpedia_id = JSONField(default=list)
    luding_id = JSONField(default=list)
    spielen_id = JSONField(default=list)
    bga_id = JSONField(default=list)

    def highest_ranking(self, ranking_type=Ranking.BGG):
        """Find the highest ever rank of the given type."""
        return (
            # pylint: disable=no-member
            self.ranking_set.filter(ranking_type=ranking_type
                                    ).order_by("rank", "-date").first())

    @property
    def highest_ranking_bgg(self):
        """Highest BGG ranking."""
        return self.highest_ranking(ranking_type=Ranking.BGG)

    @property
    def highest_ranking_factor(self):
        """Highest factor model ranking."""
        return self.highest_ranking(ranking_type=Ranking.FACTOR)

    @property
    def highest_ranking_similarity(self):
        """Highest similarity model ranking."""
        return self.highest_ranking(ranking_type=Ranking.SIMILARITY)

    class Meta:
        """meta"""

        ordering = ("-rec_rating", "-bayes_rating", "-avg_rating")
        indexes = (Index(fields=("-rec_rating", "-bayes_rating",
                                 "-avg_rating")), )

    def __str__(self):
        return str(self.name)
Beispiel #12
0
class VideoRepresentation(Representation):
    """ Video Representation entity which saves URL to video """
    video_url = URLField(null=True, max_length=1024)

    class Meta:
        db_table = "green_planet_video_representation"
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="+",
    )
    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)
    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"),
    )
    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="")
    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
    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"
             ),
        ),
        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>"),
        ),
        StreamFieldPanel("body"),
        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"),
        ),
        StreamFieldPanel("agenda"),
        StreamFieldPanel("speakers"),
    ]

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

    # Meta panels
    meta_panels = [
        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 = BasePage.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 >= get_past_event_cutoff()

    @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
Beispiel #14
0
class Ad(Model):
    APPROVAL_CHOICES = (
        ('accepted', 'قبول'),
        ('denied', 'رد'),
    )

    advertiser = ForeignKey(to=Advertiser,
                            related_name='ads',
                            verbose_name='تبلیغ کننده',
                            on_delete=CASCADE)

    approve = CharField(max_length=10,
                        choices=APPROVAL_CHOICES,
                        verbose_name='وضعیت',
                        default='denied')

    title = CharField(max_length=100, verbose_name='موضوع')

    img_url = URLField(verbose_name=' ادرس عکس تبلیغ', )

    link = URLField(verbose_name='ادرس سایت شما')

    class Meta:
        verbose_name = 'تبلیغ'
        verbose_name_plural = 'تبلیغات'

    def __str__(self):
        return str(self.advertiser) + ' : ' + str(self.title)

    @staticmethod
    def get_total_ctr(start_time, end_time):
        return Ad.objects.annotate(
            total_views=Count(F('views'),
                              distinct=True,
                              filter=Q(views__time__range=(start_time,
                                                           end_time)))
        ).filter(total_views__gt=0).annotate(
            ctr=Cast(
                Count(F('clicks'),
                      distinct=True,
                      filter=Q(clicks__time__range=(
                          start_time, end_time))), FloatField()) /
            Cast(
                Count(F('views'),
                      distinct=True,
                      filter=Q(views__time__range=(start_time, end_time)),
                      output_field=FloatField()), FloatField())).order_by(
                          '-ctr')

    @staticmethod
    def get_total_clicks_views(start_time, end_time, delta):
        ads = Ad.objects.all()
        response = dict()
        for ad in ads:
            ad_response = list()
            start = start_time
            while start < end_time:
                end = start + timezone.timedelta(hours=delta)
                d = ad.get_dict_in_time_range(start_time=start, end_time=end)
                ad_response.append(d)

                start = end

            response.update({ad: ad_response})

        return response

    def get_dict_in_time_range(self, start_time, end_time):
        clicks_count = self.clicks.filter(time__range=(start_time,
                                                       end_time)).count()

        views_count = self.views.filter(time__range=(start_time,
                                                     end_time)).count()

        d = dict()
        d.update({
            'start_time': start_time,
            'end_time': end_time,
            'total_clicks': clicks_count,
            'total_view': views_count,
        })
        return d

    def get_closest_view(self, ip, time):
        return self.views.filter(ip=ip, time__lt=time).order_by('-time')[0]
Beispiel #15
0
class Announcement(SearchableModel):
    title = CharField(max_length=255,
                      db_index=True,
                      help_text=_(u'Max length \
		255 characters, required field.'))
    slug = SlugField(max_length=255,
                     db_index=True,
                     help_text=_(u'The \
		part of the URL specific to this announcement. This field is required; \
		it autocompletes from the value you enter in the title field, but you \
		can edit it to suit your need. Allowd characters: 0-9a-z-_ If the \
		field is left empty by the time you save the announcement, the slug \
		will be automatically generated.'))
    subtitle = CharField(max_length=255,
                         blank=True,
                         help_text=_(u'Optional \
		field, max lenght 255 characters.'))
    text = TextField(help_text=_(u'This field is required.'))
    image = ImageField(max_length=200,
                       upload_to='announcements',
                       blank=True,
                       verbose_name=_(u'Main image'),
                       help_text=_(u'Optional \
		field. allowed mime types: png, jpg, jpeg, gif.'))
    img_url = URLField(
        max_length=255,
        blank=True,
        verbose_name=_(u'Image URL'),
        help_text=_(
            u'Optionally, you can provide a URL for the image you want \
		to associate with the announcement. You need to supply the URL of the \
		image (something like http://example.com/image.jpg). It will be \
		downloaded and served from your server.'))
    thumbnail = ImageSpecField(image_field='image',
                               processors=[ResizeToFit(220, 160)])
    evsdate = DateTimeField(blank=True,
                            null=True,
                            verbose_name=_(u'Event \
		starts'),
                            help_text=_(u'Optional field'))
    evedate = DateTimeField(blank=True,
                            null=True,
                            verbose_name=_(u'Event \
		ends'),
                            help_text=_(u'Optional field'))
    evlocation = CharField(blank=True,
                           verbose_name=_(u'Event location'),
                           help_text=_(u'Optional field, max 255 characters.'),
                           max_length=255)
    summary = TextField(blank=True,
                        help_text=_(u'An optional "tl;dr" \
		field. If filled, the template will output the value in a bold font, \
		above the text.'))
    metadescription = CharField(max_length=160,
                                blank=True,
                                help_text=_(u'\
		Optional field, max length 160 characters. Generates a metadescription \
		tag for search engines. If left blank, the meta tag will be filled \
		with the first 160 characters of the Text field.'))
    noindex = BooleanField(default=False,
                           help_text=_(u'Check if you have \
		reasons to stop search engines from indexing this announcement.'))
    date = DateTimeField(
        default=datetime.now,
        db_index=True,
        verbose_name=_(u'\
		Publish date'),
        help_text=_('Announcement\'s publishing date and time, \
		defaults to now. If you set a future date, the announcement will be \
		published at that time.'))
    expdate = DateTimeField(
        blank=True,
        null=True,
        verbose_name=_(u'Expiration \
		date'),
        help_text=_(u'Optional field. If you set this date, the \
		announcement will become unavailble on the public section of the \
		website at that time.'))
    timestamp = DateTimeField(auto_now=True, db_index=True)
    public = BooleanField(default=False,
                          help_text=_(u'Check this box \
		to make the announcement public. Uncheck if you need to stop it from \
		appearing on the website.'))

    objects = AnnouncementsManager()
    search_objects = SearchManager(fields=(
        'title',
        'subtitle',
        'text',
        'summary',
    ))

    class Meta:
        verbose_name = u'Announcement'
        verbose_name_plural = u'Announcements'
        ordering = ('-date', '-id')
        get_latest_by = 'date'

    def __unicode__(self):
        return u'%s' % self.title

    def __init__(self, *args, **kwargs):
        super(Announcement, self).__init__(*args, **kwargs)

        # on init, previous and next announcements are unknown,
        # so they should default to None
        self._next = None
        self._prev = None

    def save(self, *args, **kwargs):
        # before save, make sure there is a slug
        if not self.slug:
            self.slug = slugify(self.title)

        # send data to the database
        super(Announcement, self).save(*args, **kwargs)

        # after save
        # invalidate cache (next/prev announcement, homepage announcements)
        if self.public is True:
            i = self.id
            keys = ('dcae_ann_%s' % i, 'dcae_anp_%s' % i, 'dcae_han')
            for key in keys:
                try:
                    cache.delete(key)
                except Exception, e:
                    logger.info(e)

        # now try retreive the remote image, if set and if no image has been
        # uploaded
        if self.img_url and not self.image:
            # first, check if the image has already been downloaded
            from django.conf import settings
            from utils.func import image_name_from_url, file_exists

            expected = '%s/announcements/%s' % (
                settings.MEDIA_ROOT, image_name_from_url(self.img_url))

            if file_exists(expected):
                pass  # if the file has already been downloaded, execution stops here

            else:  # image hasn't been downloaded yet

                # check if the provided url is an actual image
                from utils.func import is_url_image

                if is_url_image(self.img_url):
                    # download file

                    url = self.img_url
                    path = '%s/announcements/%s' % (
                        settings.MEDIA_ROOT, image_name_from_url(self.img_url))

                    try:
                        from urllib import urlretrieve
                        urlretrieve(url, path)
                    except Exception, e:
                        logger.info(e)
                else:
                    logger.info(
                        u'The provided image URL for the Announcement "%s" was not a real image. Please check again.'
                        % self.title)
Beispiel #16
0
class App(TranslatableModel):
    objects = AppManager()
    id = CharField(max_length=256,
                   unique=True,
                   primary_key=True,
                   verbose_name=_('ID'),
                   help_text=_('app ID, identical to folder name'))
    categories = ManyToManyField('Category', verbose_name=_('Category'))
    translations = TranslatedFields(
        name=CharField(max_length=256,
                       verbose_name=_('Name'),
                       help_text=_('Rendered app name for users')),
        summary=CharField(
            max_length=256,
            verbose_name=_('Summary'),
            help_text=_('Short text describing the app\'s purpose')),
        description=TextField(verbose_name=_('Description'),
                              help_text=_('Will be rendered as Markdown')))
    # resources
    user_docs = URLField(max_length=256,
                         blank=True,
                         verbose_name=_('User documentation URL'))
    admin_docs = URLField(max_length=256,
                          blank=True,
                          verbose_name=_('Admin documentation URL'))
    developer_docs = URLField(max_length=256,
                              blank=True,
                              verbose_name=_('Developer documentation URL'))
    issue_tracker = URLField(max_length=256,
                             blank=True,
                             verbose_name=_('Issue tracker URL'))
    website = URLField(max_length=256, blank=True, verbose_name=_('Homepage'))
    discussion = URLField(max_length=256, blank=True, verbose_name=_('Forum'))
    created = DateTimeField(auto_now_add=True,
                            editable=False,
                            verbose_name=_('Created at'))
    last_modified = DateTimeField(auto_now=True,
                                  editable=False,
                                  db_index=True,
                                  verbose_name=_('Updated at'))
    owner = ForeignKey(settings.AUTH_USER_MODEL,
                       verbose_name=_('App owner'),
                       on_delete=CASCADE,
                       related_name='owned_apps')
    co_maintainers = ManyToManyField(settings.AUTH_USER_MODEL,
                                     blank=True,
                                     verbose_name=_('Co-Maintainers'),
                                     related_name='co_maintained_apps')
    authors = ManyToManyField('AppAuthor',
                              blank=True,
                              related_name='apps',
                              verbose_name=_('App authors'))
    is_featured = BooleanField(verbose_name=_('Featured'), default=False)
    rating_recent = FloatField(verbose_name=_('Recent rating'), default=0.5)
    rating_overall = FloatField(verbose_name=_('Overall rating'), default=0.5)
    rating_num_recent = IntegerField(
        verbose_name=_('Number of recently submitted ratings'), default=0)
    rating_num_overall = IntegerField(
        verbose_name=_('Number of overall submitted ratings'), default=0)
    last_release = DateTimeField(editable=False,
                                 db_index=True,
                                 verbose_name=_('Last release at'),
                                 default=timezone.now)
    certificate = TextField(verbose_name=_('Certificate'))
    ownership_transfer_enabled = BooleanField(
        verbose_name=_('Ownership transfer enabled'),
        default=False,
        help_text=_('If enabled, a user can try to register the same app '
                    'again using the public certificate and signature. If he '
                    'does, the app will be transferred to him.'))
    is_integration = BooleanField(verbose_name=_('Integration (i.e. Outlook '
                                                 'plugin)'),
                                  default=False)
    approved = BooleanField(verbose_name=_('Used to approve integrations'),
                            default=False)

    class Meta:
        verbose_name = _('App')
        verbose_name_plural = _('Apps')

    def __str__(self) -> str:
        return self.name

    def can_update(self, user: User) -> bool:
        return self.owner == user or user in self.co_maintainers.all()

    def can_delete(self, user: User) -> bool:
        return self.owner == user

    @property
    def discussion_url(self):
        if self.discussion:
            return self.discussion
        else:
            return '%s/c/apps/%s' % (settings.DISCOURSE_URL,
                                     self.id.replace('_', '-'))

    def _get_grouped_releases(self, get_release_func):
        releases = NextcloudRelease.objects.all()
        versions = map(lambda r: r.version, releases)
        compatible_releases = map(lambda v: (v, get_release_func(v)), versions)
        grouped_releases = group_by_main_version(dict(compatible_releases))
        # deduplicate releases
        result = {}
        for version, releases in grouped_releases.items():
            result[version] = list(distinct(releases, lambda r: r.version))
        return result

    def releases_by_platform_v(self):
        """Looks up all compatible stable releases for each platform
        version.

        Example of returned dict:

        {'9.1': [<AppRelease object>, <AppRelease object>],
        '9.0': [<AppRelease object>]}

        :return dict with all compatible stable releases for each platform
                version.
        """
        return self._get_grouped_releases(self.compatible_releases)

    def unstable_releases_by_platform_v(self):
        """Looks up all compatible unstable releases for each platform version.

        Example of returned dict:

        {'9.1': [<AppRelease object>, <AppRelease object>],
        '9.0': [<AppRelease object>]}

        :return dict with all compatible unstable releases for each platform
                version.
        """
        return self._get_grouped_releases(self.compatible_unstable_releases)

    def latest_releases_by_platform_v(self):
        """Looks up the latest stable and unstable release for each platform
        version.

        Example of returned dict:

        {'9.1': {
            'stable': <AppRelease object>,
            'unstable': <AppRelease object>
        },
        '9.0': {
            'stable': <AppRelease object>
        }}

        :return dict with the latest stable and unstable release for each
                platform version.
        """
        stable = self.releases_by_platform_v()
        unstable = self.unstable_releases_by_platform_v()

        def filter_latest(pair):
            version, releases = pair
            return (version, self._latest(releases))

        latest_stable = dict(map(filter_latest, stable.items()))
        latest_unstable = dict(map(filter_latest, unstable.items()))
        all_versions = set(chain(latest_stable.keys(), latest_unstable.keys()))

        def stable_or_unstable_releases(ver):
            return (ver, {
                'stable': latest_stable.get(ver, None),
                'unstable': latest_unstable.get(ver, None)
            })

        return dict(map(stable_or_unstable_releases, all_versions))

    def compatible_releases(self, platform_version, inclusive=True):
        """Returns all stable releases of this app that are compatible
        with the given platform version.

        :param inclusive: Use inclusive version check (see
                          AppRelease.is_compatible()).
        :return a sorted list of all compatible stable releases.
        """

        return sorted(
            filter(
                lambda r: r.is_compatible(platform_version, inclusive) and
                not r.is_unstable, self.releases.all()),
            key=lambda r: AppSemVer(r.version, r.is_nightly, r.last_modified),
            reverse=True)

    def compatible_unstable_releases(self, platform_version, inclusive=True):
        """Returns all unstable releases of this app that are compatible with
        the given platform version.

        :param inclusive: Use inclusive version check (see
                          AppRelease.is_compatible()).
        :return a sorted list of all compatible unstable releases.
        """

        return sorted(
            filter(
                lambda r: r.is_compatible(platform_version, inclusive) and r.
                is_unstable, self.releases.all()),
            key=lambda r: AppSemVer(r.version, r.is_nightly, r.last_modified),
            reverse=True)

    def _latest(self, releases):
        try:
            return max(releases,
                       key=lambda r: AppSemVer(r.version, r.is_nightly, r.
                                               last_modified))
        except ValueError:
            return None

    def save(self, *args, **kwargs):
        # If the certificate has changed, delete all releases.
        try:
            if self.pk is not None:
                orig = App.objects.get(pk=self.pk)
                current = self.certificate.replace('\r', '').strip()
                former = orig.certificate.replace('\r', '').strip()
                # for some reason the django admin inserts \r\n for \n so
                # saving a model in the admin with the same cert kills all
                # releases
                if current != former:
                    self.releases.all().delete()
        except self.DoesNotExist:
            pass
        super().save(*args, **kwargs)
class Staff(TranslatableModel):
    #region           -----Translation-----
    translations = TranslatedFields(
        second_name=CharField(max_length=40,
                              blank=False,
                              verbose_name=_("Second name")),
        first_name=CharField(max_length=40,
                             blank=False,
                             verbose_name=_("First name")),
        third_name=CharField(max_length=40,
                             blank=False,
                             verbose_name=_("Third name")),
        rank=CharField(max_length=300, blank=True, verbose_name=_("Rank")),
        methodical_works=HTMLField(blank=True,
                                   verbose_name=_("Methodical works")),
        description=HTMLField(blank=True, verbose_name=_("Description")),
        ndr_theme=TextField(blank=True,
                            verbose_name=_("Topics of research work")))
    #endregion

    #region           -----Information-----
    google_scholar = URLField(blank=True,
                              verbose_name=_("Google Scholar"),
                              null=True)
    web_of_science = URLField(blank=True,
                              verbose_name=_("Web Of Science"),
                              null=True)
    researchgate = URLField(blank=True,
                            verbose_name=_("Researchgate"),
                            null=True)
    scopus = URLField(verbose_name=_("Scopus"), blank=True, null=True)
    orcid = URLField(verbose_name=_("ORCID"), blank=True, null=True)
    photo = ImageField(verbose_name=_("Photo"),
                       upload_to="photos",
                       blank=False)
    phone = CharField(max_length=20,
                      blank=True,
                      null=True,
                      verbose_name=_("Phone number"))
    emails = MultiEmailField(blank=True)
    #endregion

    #region            -----Relation-----
    disciplines = ManyToManyField(Discipline, blank=True)
    books = ManyToManyField(Book, blank=True)
    rewards = ManyToManyField("Reward",
                              blank=True,
                              verbose_name=_("Rewards"),
                              related_name="staff_rewards")

    #endregion

    #region            -----Metadata-----
    class Meta(object):
        verbose_name_plural = _("Staff")
        verbose_name = _("Staff")

    #endregion

    #region         -----Internal Methods-----
    def get_absolute_url(self) -> str:
        """@return link to model"""
        return reverse('teacher', kwargs={'teacher_id': self.pk})

    def searching_fields(self) -> List[str]:
        """@return translated fields"""
        return [
            "translations__first_name", "translations__methodical_works",
            "translations__second_name", "translations__description",
            "translations__third_name"
        ]

    def __str__(self) -> str:
        """@return staff information"""
        return (self.second_name + " " + self.first_name + " " +
                self.third_name)
Beispiel #18
0
class YTChannel(Model):
    url = URLField(unique=True)
    title = CharField(max_length=70, blank=True)

    def __str__(self):
        return self.title
Beispiel #19
0
class Poodle(BaseModel):
    slug = AutoSlugField(default=None,
                         unique=True,
                         populate_from="name_registered")
    pd_id = IntegerField(verbose_name="PD ID", unique=True, null=True)
    name_call = CharField(verbose_name="Call Name",
                          max_length=50,
                          blank=True,
                          null=True,
                          default="")
    name_registered = CharField(
        verbose_name="Registered Name",
        max_length=500,
        blank=True,
        null=True,
        default="",
    )
    owners = ManyToManyField(Person,
                             verbose_name="Owner(s)",
                             related_name="owns_poodles",
                             blank=True)
    breeders = ManyToManyField(Person,
                               verbose_name="Breeder(s)",
                               related_name="bred_poodles",
                               blank=True)
    pd_owner = CharField(verbose_name="PD Owner",
                         max_length=200,
                         null=True,
                         blank=True,
                         default="")
    pd_breeder = CharField(verbose_name="PD Breeder",
                           max_length=200,
                           null=True,
                           blank=True,
                           default="")
    origin_country = ForeignKey(Country,
                                verbose_name="Country",
                                on_delete=PROTECT,
                                null=True)
    honorifics = CharField(verbose_name="Honorifics",
                           max_length=50,
                           blank=True,
                           null=True,
                           default="")
    chic = CharField(verbose_name="CHIC",
                     max_length=50,
                     null=True,
                     blank=True,
                     default="")
    ofa_url = URLField(verbose_name="OFA URL",
                       max_length=300,
                       **NULL_AND_BLANK,
                       default="")
    akc = CharField(verbose_name="AKC",
                    max_length=50,
                    null=True,
                    blank=True,
                    default="")
    akc_dna = CharField(verbose_name="AKC DNA",
                        max_length=50,
                        **NULL_AND_BLANK,
                        default="")
    ukc = CharField(verbose_name="UKC",
                    max_length=50,
                    **NULL_AND_BLANK,
                    default="")
    addtl = CharField(
        verbose_name="Addtl Reg",
        max_length=50,
        null=True,
        blank=True,
        default="",
    )
    sex = CharField(verbose_name="Sex", max_length=1, choices=SEX_CHOICES)
    pd_color = CharField(verbose_name="PD Color",
                         max_length=100,
                         blank=True,
                         null=True,
                         default="")
    height = CharField(verbose_name="Height",
                       max_length=10,
                       blank=True,
                       null=True,
                       default="")
    color = ForeignKey(Color,
                       verbose_name="Color",
                       on_delete=PROTECT,
                       null=True)
    dob_dod = CharField(verbose_name="Lifespan",
                        max_length=60,
                        blank=True,
                        null=True,
                        default="")
    dob = CharField(verbose_name="Date of Birth",
                    max_length=12,
                    blank=True,
                    null=True)
    dod = CharField(verbose_name="Date of Death",
                    max_length=12,
                    blank=True,
                    null=True)
    sire = ForeignKey("self",
                      verbose_name="Sire",
                      related_name="poodle_sire",
                      null=True,
                      on_delete=PROTECT)
    dam = ForeignKey("self",
                     verbose_name="Dam",
                     related_name="poodle_dam",
                     null=True,
                     on_delete=PROTECT)
    pedigree_src = CharField(verbose_name="Pedigree Source",
                             max_length=100,
                             null=True,
                             blank=True,
                             default="")
    variety = CharField(verbose_name="Variety",
                        max_length=1,
                        null=True,
                        blank=True,
                        default="",
                        choices=VARIETY_CHOICES)
    pd_variety = CharField(
        verbose_name="PD Variety",
        max_length=1,
        null=True,
        blank=True,
        default="",
    )
    titles_prefix = ManyToManyField(Title,
                                    verbose_name="Prefix Titles",
                                    related_name="poodles_prefix",
                                    blank=True)
    titles_suffix = ManyToManyField(Title,
                                    verbose_name="Suffix Titles",
                                    related_name="poodles_suffix",
                                    blank=True)
    vwd_clearance = CharField(verbose_name="Von Willebrand Disease",
                              max_length=100,
                              blank=True,
                              null=True,
                              default="")
    thyroid_clearance = CharField(verbose_name="Thyroid",
                                  max_length=100,
                                  blank=True,
                                  null=True,
                                  default="")
    legg_c_p_clearance = CharField(
        verbose_name="Legg-Calvé-Perthes Disease (LCP)",
        max_length=100,
        blank=True,
        null=True,
        default="")
    pra_optigen_clearance = CharField(
        verbose_name="Progressive Retinal Atrophy (PRA)",
        max_length=100,
        blank=True,
        null=True,
        default="")
    neonatal_enceph_clearance = CharField(
        verbose_name="Neonatal Encephalopathy",
        max_length=100,
        blank=True,
        null=True,
        default="")
    hip_clearance = CharField(verbose_name="Hip Dysplasia",
                              max_length=100,
                              blank=True,
                              null=True,
                              default="")
    eye_clearance = CharField(verbose_name="Eye Examination",
                              max_length=100,
                              blank=True,
                              null=True,
                              default="")
    sa_clearance = CharField(verbose_name="Sebaceous Adenitis (SA)",
                             max_length=100,
                             blank=True,
                             null=True,
                             default="")
    heart_clearance = CharField(verbose_name="Cardiac Disease",
                                max_length=100,
                                blank=True,
                                null=True,
                                default="")
    elbow_clearance = CharField(verbose_name="Elbow Dysplasia",
                                max_length=100,
                                blank=True,
                                null=True,
                                default="")
    patella_clearance = CharField(verbose_name="Patellar Luxation",
                                  max_length=100,
                                  blank=True,
                                  null=True,
                                  default="")
    health_information = CharField(verbose_name="Other Health Info",
                                   max_length=100,
                                   blank=True,
                                   null=True,
                                   default="")
    comments = TextField(verbose_name="Comments", **NULL_AND_BLANK, default="")
    is_viewable = BooleanField(verbose_name="Viewable?", default=False)

    class Meta(BaseModel.Meta):
        verbose_name_plural = "Poodles"

    def __str__(self):
        if self.name_call:
            return '{n} "{c}"'.format(n=self.name_registered, c=self.name_call)
        else:
            return self.name_registered

    def get_absolute_url(self):
        return reverse("core:poodle-detail", args=[str(self.slug)])

    def get_owners(self):
        return ", ".join([o.full_name for o in self.owners.all()])

    def get_breeders(self):
        return ", ".join([o.full_name for o in self.breeders.all()])

    def get_titles_p(self):
        return " ".join([o.abbr for o in self.titles_prefix.all()])

    def get_titles_s(self):
        return " ".join([o.abbr for o in self.titles_suffix.all()])

    def offspring(self):
        return Poodle.objects.filter(Q(sire=self.id)
                                     | Q(dam=self.id)).order_by(
                                         'sire', 'dam').select_related(
                                             "color",
                                             "origin_country",
                                             "sire",
                                             "dam",
                                         ).prefetch_related(
                                             "color",
                                             "origin_country",
                                             "sire",
                                             "dam",
                                         )

    def siblings_full(self):
        return Poodle.objects.filter(Q(sire=self.sire) & Q(
            dam=self.dam)).exclude(id=self.id).order_by('name_registered')

    def siblings_damside(self):
        return Poodle.objects.filter(~Q(sire=self.sire)
                                     & Q(dam=self.dam)).exclude(
                                         id=self.id).order_by('dam')

    def siblings_sireside(self):
        return Poodle.objects.filter(Q(sire=self.sire)
                                     & ~Q(dam=self.dam)).exclude(
                                         id=self.id).order_by('sire')

    def images(self):
        return self.poodles_images.all()

    @staticmethod
    def autocomplete_search_fields():
        return ('name_registered__icontains', 'name_call__icontains')
Beispiel #20
0
class User(AbstractUser):
    # First Name and Last Name do not cover name patterns
    # around the globe.
    nickname = CharField(verbose_name="昵称",
                         null=True,
                         blank=True,
                         max_length=255,
                         default='')
    name = CharField(verbose_name="真实姓名",
                     null=True,
                     blank=True,
                     max_length=255,
                     default='')
    avatar = ImageField(upload_to='users/avatars/',
                        null=True,
                        blank=True,
                        verbose_name='用户头像',
                        default='')
    sex = CharField(verbose_name="性别",
                    choices=(("M", "男"), ("F", "女"), ("P", "不公开")),
                    default="P",
                    max_length=50)
    birthday = DateField(verbose_name="生日",
                         null=True,
                         blank=True,
                         default=timezone.now)
    position = CharField(verbose_name="职位",
                         null=True,
                         blank=True,
                         max_length=255,
                         default='')
    company = CharField(verbose_name="公司",
                        null=True,
                        blank=True,
                        max_length=255,
                        default='')
    education = CharField(verbose_name="学历",
                          null=True,
                          blank=True,
                          max_length=255,
                          default='')
    industry = CharField(verbose_name="行业",
                         null=True,
                         blank=True,
                         max_length=255,
                         default='')
    introduction = CharField(verbose_name="简介",
                             null=True,
                             blank=True,
                             max_length=255,
                             default='')
    website = URLField(verbose_name="网站",
                       null=True,
                       blank=True,
                       max_length=255,
                       default='')
    skill = TaggableManager(help_text='多个标签使用英文逗号(,)隔开',
                            blank=True,
                            verbose_name='技能')
    # skill = CharField(verbose_name='技能', blank=True,null=True, default='', max_length=512)
    # homepage = ManyToManyField(Homepages, null=True, blank=True, verbose_name="个人主页")
    # medal = ForeignKey(Medal, on_delete=models.CASCADE, verbose_name="勋章")

    created_at = DateField(auto_now_add=True, verbose_name='创建时间')

    class Meta:
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

    def get_profile_name(self):
        if self.nickname:
            return self.nickname
        return self.username

    def get_absolute_url(self):
        return reverse("users:detail", kwargs={"username": self.username})
Beispiel #21
0
class HomePage(BasePage):
    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="+",
    )
    featured = StreamField(
        StreamBlock(
            [
                (
                    "post",
                    PageChooserBlock(target_model=(
                        "articles.Article",
                        "externalcontent.ExternalArticle",
                    )),
                ),
                (
                    "content_page",
                    PageChooserBlock(target_model=("content.ContentPage", )),
                ),
                ("external_page", FeaturedExternalBlock()),
                (
                    "video",
                    PageChooserBlock(target_model=(
                        "videos.Video",
                        # NB: ExternalVideo is NOT allowed on the homepage
                        # "externalcontent.ExternalVideo"
                    )),
                ),
            ],
            min_num=2,
            max_num=5,
            required=False,
        ),
        null=True,
        blank=True,
        help_text=
        ("Optional space for featured posts, videos or links, min. 2, max. 5. "
         "Note that External Video is NOT allowed here."),
    )

    featured_people = StreamField(
        StreamBlock(
            [("person", PageChooserBlock(target_model="people.Person"))],
            max_num=3,
            required=False,
        ),
        null=True,
        blank=True,
        help_text="Optional featured people, max. 3",
    )

    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=DESCRIPTION_MAX_LENGTH,
                                 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 = BasePage.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("featured"),
        StreamFieldPanel("featured_people"),
        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"),
                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"),
    ])

    @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.published_objects.filter(parent_topics__isnull=True)
Beispiel #22
0
class HierarchicUser(TreeModelMixin, AbstractUser):
    show_email = BooleanField(_('afficher l’email'), default=False)
    website = URLField(_('site internet'), blank=True)
    website_verbose = CharField(
        _('nom affiché du site internet'), max_length=50, blank=True)

    legal_person = BooleanField(
        _('personne morale'), default=False,
        help_text=_('Cochez si vous êtes une institution ou un ensemble.'))
    content_type = ForeignKey(
        ContentType, blank=True, null=True,
        limit_choices_to={'model__in': _get_valid_modelnames_func()},
        verbose_name=_('type d’autorité associée'), on_delete=CASCADE)
    object_id = PositiveIntegerField(_('identifiant de l’autorité associée'),
                                     blank=True, null=True)
    content_object = GenericForeignKey()

    mentor = ForeignKey(
        'self', null=True, blank=True, related_name='disciples',
        verbose_name=_('responsable scientifique'),
        limit_choices_to={'willing_to_be_mentor__exact': True},
        on_delete=CASCADE)
    path = PathField(order_by=('last_name', 'first_name', 'username'),
                     db_index=True)
    willing_to_be_mentor = BooleanField(
        _('Veut être responsable scientifique'), default=False)

    avatar = ImageField(_('photographie d’identité'), upload_to='avatars/',
                        blank=True, null=True)

    presentation = TextField(
        _('présentation'), blank=True, validators=[MaxLengthValidator(5000)])
    fonctions = TextField(_('fonctions au sein de l’équipe'), blank=True,
                          validators=[MaxLengthValidator(200)])
    literature = TextField(_('publications'), blank=True)

    objects = HierarchicUserManager()

    class Meta(object):
        ordering = ('last_name', 'first_name')
        verbose_name = _('utilisateur')
        verbose_name_plural = _('utilisateurs')

    def __str__(self, tags=False):
        return self.html(tags=False)

    def get_full_name(self, tags=False):
        full_name = f'{self.first_name} {sc(self.last_name, tags=tags)}'
        return full_name.strip()

    def html(self, tags=True):
        txt = self.get_full_name(tags=tags) or self.get_username()
        return href(self.get_absolute_url(), txt, tags=tags)

    def link(self, tags=True):
        return self.html(tags=tags)

    @permalink
    def get_absolute_url(self):
        return 'user_profile', (self.username,)

    def website_link(self):
        return href(self.website, self.website_verbose or self.website,
                    new_tab=True)

    def email_link(self):
        return href(f'mailto:{self.email}', self.email)

    def dossiers_edites(self):
        return apps.get_model('dossiers.DossierDEvenements').objects.filter(
            editeurs_scientifiques=self
        ).exclude(parent__editeurs_scientifiques=self)

    @staticmethod
    def autocomplete_search_fields():
        return ('first_name__unaccent__icontains',
                'last_name__unaccent__icontains')
Beispiel #23
0
class ExternalFile(Model):
    url = URLField(default="", blank=True)
    label = TextField()
class Kid(Model):
    class Color(IntegerChoices):
        BLACK = 1, _("Preto")
        BROWN = 2, _("Castanhos")
        BLONDE = 3, _("Loiro")
        RED = 4, _("Ruivo")
        BLUE = (
            5,
            _("Azul"),
        )
        SWARTHY = 6, _("Morena")
        WHITE = 7, _("Branca")

    # required fiels
    name = CharField("Nome", max_length=255, db_index=True, unique=True)
    url = URLField("URL")
    full_text = TextField()

    # optional indexed fields
    dob = DateField("Data de nascimento", null=True, blank=True, db_index=True)
    missing_since = DateField(
        "Desaparecida(o) desde", null=True, blank=True, db_index=True
    )
    eyes = CharField(
        "Cor dos olhos",
        max_length=50,
        choices=Color.choices,
        null=True,
        blank=True,
        db_index=True,
    )
    hair = CharField(
        "Cor dos cabelos",
        max_length=50,
        choices=Color.choices,
        null=True,
        blank=True,
        db_index=True,
    )
    skin = CharField(
        "Cor da pele",
        max_length=50,
        choices=Color.choices,
        null=True,
        blank=True,
        db_index=True,
    )

    # optional fields
    mother = CharField("Mãe", max_length=255, null=True, blank=True)
    father = CharField("Pai", max_length=255, null=True, blank=True)
    last_seen_at = CharField(
        "Local onde foi vista(o) pela última vez", max_length=255, null=True, blank=True
    )
    age_at_occurrence = IntegerField("Idade quando desapareceu", null=True, blank=True)

    class Meta:
        verbose_name = "criança"
        ordering = ("name",)

    def __str__(self):
        return self.name
Beispiel #25
0
class ExternalContent(BasePage):
    is_external = True
    subpage_types = []

    # Card fields
    description = RichTextField(
        blank=True,
        default="",
        features=RICH_TEXT_FEATURES_SIMPLE,
        help_text="Optional short text description, max. 400 characters",
        max_length=400,
    )
    external_url = URLField(
        "URL",
        blank=True,
        default="",
        help_text=(
            "The URL that this content links to, max. 2048 characters "
            "for compatibility with older web browsers"
        ),
        max_length=2048,
    )
    image = ForeignKey(
        "mozimages.MozImage",
        null=True,
        blank=True,
        on_delete=SET_NULL,
        related_name="+",
    )

    card_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"
            ),
        ),
        FieldPanel("external_url"),
    ]

    settings_panels = BasePage.settings_panels + [FieldPanel("slug")]

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

    class Meta:
        verbose_name_plural = "External Content"

    def get_full_url(self, request=None):
        return self.external_url

    def get_url(self, request=None, current_site=None):
        return self.external_url

    def relative_url(self, current_site, request=None):
        return self.external_url

    @property
    def url(self):
        return self.external_url

    def serve_preview(self, request, mode_name):
        # ExternalContent subclasses don't preview like regular Pages: we just need
        # to show where they link to.
        return HttpResponseRedirect(self.external_url)
Beispiel #26
0
class Film(Model):
    titre = CharField(max_length=200, unique=True)
    respo = ForeignKey(User)
    description = TextField()
    slug = SlugField(unique=True, blank=True)
    annee_sortie = IntegerField(choices=CHOIX_ANNEES,
                                blank=True,
                                null=True,
                                verbose_name="Année de sortie")

    titre_vo = CharField(max_length=200,
                         blank=True,
                         null=True,
                         verbose_name="Titre en VO")
    imdb = URLField(blank=True, null=True, verbose_name="IMDB")
    allocine = URLField(blank=True, null=True, verbose_name="Allociné")
    realisateur = CharField(max_length=200,
                            null=True,
                            blank=True,
                            verbose_name="Réalisateur")
    duree = CharField(max_length=20,
                      null=True,
                      blank=True,
                      verbose_name="Durée")
    duree_min = IntegerField("Durée en minutes", null=True)

    vu = BooleanField(default=False)

    imdb_id = CharField(max_length=10,
                        verbose_name="id IMDB",
                        null=True,
                        blank=True)

    imdb_poster_url = URLField(blank=True,
                               null=True,
                               verbose_name="URL du poster")
    imdb_poster = ImageField(upload_to='cine/posters', blank=True, null=True)

    def save(self, *args, **kwargs):
        update = self.pk is None
        if not update:
            orig = Film.objects.get(pk=self.pk)
            if orig.slug != self.slug or orig.imdb_poster_url != self.imdb_poster_url:
                update = True
        if update:
            self.slug = slugify(self.titre)
            img = requests.get(self.imdb_poster_url)
            if img.status_code == requests.codes.ok:
                img_temp = NamedTemporaryFile(delete=True)
                img_temp.write(img.content)
                img_temp.flush()
                self.imdb_poster.save(self.slug, File(img_temp), save=False)
                img_temp.close()
        super(Film, self).save(*args, **kwargs)

        if update:
            self.nouveau()

    def nouveau(self):
        # Création des votes & envoi des mails de notif
        film_url = self.get_full_url()
        vote_url = full_url(reverse('cine:votes'))

        message = "Hello :)\n\n%s a proposé un nouveau film : %s (%s)' ; " % (
            self.respo, self.titre, film_url)
        message += "tu peux donc aller actualiser ton classement (%s) \\o/ \n\n @+!" % vote_url

        for cinephile in get_cinephiles():
            vote = Vote.objects.get_or_create(film=self, cinephile=cinephile)
            if vote[1] and settings.PROD:
                cinephile.email_user('[CinéNim] Film ajouté !', message)

    def get_absolute_url(self):
        return reverse('cine:film', kwargs={'slug': self.slug})

    def get_full_url(self):
        return full_url(self.get_absolute_url())

    def get_description(self):
        return self.description.replace('\r\n', '\\n')

    def score_absolu(self):
        score = 0
        for vote in self.vote_set.all():
            score -= vote.choix
        return score

    @staticmethod
    def get_imdb_dict(imdb_id):
        try:
            imdb_id = re.search(r'tt\d+', imdb_id).group()
            imdb_infos = requests.get(IMDB_API_URL, params={
                'i': imdb_id
            }).json()
            return {
                'realisateur':
                imdb_infos['Director'],
                'description':
                imdb_infos['Plot'],
                'imdb_poster_url':
                imdb_infos['Poster'],
                'annee_sortie':
                imdb_infos['Year'],
                'titre':
                imdb_infos['Title'],
                'titre_vo':
                imdb_infos['Title'],
                'duree_min':
                int(
                    timedelta(**dict([
                        (key, int(value) if value else 0)
                        for key, value in re.search(
                            r'((?P<hours>\d+) h )?(?P<minutes>\d+) min',
                            imdb_infos['Runtime']).groupdict().items()
                    ])).seconds / 60),  # TGCM
                'imdb_id':
                imdb_id,
                'imdb':
                'http://www.imdb.com/title/%s/' % imdb_id,
            }
        except:
            return {}

    def __str__(self):
        return self.titre
Beispiel #27
0
class UserInfo(Model):
    class Meta:
        verbose_name = '用户信息'
        verbose_name_plural = '用户信息表'

    UserModel = settings.AUTH_USER_MODEL
    user = OneToOneField(UserModel, related_name='user_info')
    stu_id = PositiveIntegerField(
        '学号', unique=True, validators=[RegexValidator(r'\d{10}', '学号为10位数字')])
    id_card_number = CharField(
        '身份证号',
        max_length=18,
        unique=True,
        null=True,
        validators=[RegexValidator(r'\d{17}[xX\d]{1}', '身份证号格式不正确')],
        editable=False)
    sys_password = CharField('教务系统密码', max_length=32)

    name = CharField('姓名', max_length=10, null=True)
    avatar = URLField('照片', null=True)
    sex = CharField('性别',
                    max_length=1,
                    choices=[('男', '男'), ('女', '女')],
                    null=True)
    birthday = DateTimeField('生日', null=True)
    phone = CharField('联系电话',
                      max_length=13,
                      null=True,
                      validators=[
                          RegexValidator(r'\d{11}|\d{4}-\d{7}',
                                         '电话格式为11位数字或 0000-1234567')
                      ])
    home_phone = CharField('家庭电话',
                           max_length=13,
                           null=True,
                           validators=[
                               RegexValidator(r'\d{11}|\d{4}-\d{7}',
                                              '电话格式为11位数字或 0000-1234567')
                           ])

    high_school = CharField('毕业高中', max_length=20, null=True)
    college = CharField('学院简称', max_length=20, null=True)
    major = CharField('专业简称', max_length=20, null=True)
    klass = CharField('班级简称', max_length=20, null=True)

    nation = CharField('民族', max_length=10, null=True)
    native_place = CharField('籍贯', max_length=10, null=True)

    poi_id = IntegerField('poi数据id', unique=True, null=True)
    qq = IntegerField('QQ',
                      unique=True,
                      null=True,
                      validators=[RegexValidator(r'\d{5,15}', 'QQ号码最少为5位数字')])

    address = CharField('家庭地址', max_length=128, null=True)

    def sync_info_from_hfut(self):
        stu = StuLib(self.stu_id, self.sys_password)
        stu_info = stu.get_stu_info()
        res = lbs_storage.list_poi(
            GEOTABLE_ID,
            stu_id=','.join([unicode(self.stu_id),
                             unicode(self.stu_id)]))
        if res['size'] == 1:
            lbs_storage.delete_poi(GEOTABLE_ID, res['pois'][0]['id'])
            hfut_stu_location_logger.warning(
                '已存在学号为 {:d} 的 poi 数据, 已删除'.format(self.stu_id))
        loc = lbs_api.geocoding(stu_info['家庭地址'])['result']['location']
        res = lbs_storage.create_poi(
            GEOTABLE_ID,
            title='-'.join([stu_info['班级简称'], stu_info['姓名']]),
            latitude=loc['lat'],
            longitude=loc['lng'],
            address=stu_info['家庭地址'],
            avatar=stu_info['照片'],
            name=stu_info['姓名'],
            stu_id=stu.stu_id,
            sex=stu_info['性别'],
            high_school=stu_info['毕业高中'],
            college=stu_info['学院简称'],
            major=stu_info['专业简称'],
            klass=stu_info['班级简称'],
            tags=' '.join([
                stu_info['性别'], stu_info['毕业高中'], stu_info['学院简称'],
                stu_info['专业简称'], stu_info['班级简称']
            ]))
        hfut_stu_location_logger.info('成功新建学号为 {:d} 的 poi 数据'.format(
            self.stu_id))
        self.poi_id = res['id']
        self.id_card_number = stu_info['身份证号']
        self.avatar = stu_info['照片']
        self.name = stu_info['姓名']
        self.sex = stu_info['性别']
        self.birthday = datetime.strptime(stu_info['出生日期'], '%Y-%m-%d')
        self.phone = stu_info['联系电话']
        self.home_phone = stu_info['家庭电话']
        self.high_school = stu_info['毕业高中']
        self.college = stu_info['学院简称']
        self.major = stu_info['专业简称']
        self.klass = stu_info['班级简称']
        self.nation = stu_info['民族']
        self.native_place = stu_info['籍贯']
        self.address = stu_info['家庭地址']
        self.save()

    def delete_data(self, with_poi=True):
        self.delete()
        if with_poi:
            lbs_storage.delete_poi(GEOTABLE_ID, self.poi_id)

    def filter_info_by_config(self):
        # todo: 完善详细资料获取功能
        info = {}
        if self.user_info_config.show_qq:
            info['QQ'] = self.qq
        if self.user_info_config.show_phone:
            info['联系电话'] = self.phone
        if self.user_info_config.show_home_phone:
            info['家庭电话'] = self.home_phone
        if self.user_info_config.show_birthday:
            info['生日'] = self.birthday
        if self.user_info_config.show_avatar:
            info['照片'] = self.avatar
        return info

    def __unicode__(self):
        return ' '.join([unicode(self.stu_id), self.name])
Beispiel #28
0
class MessageHistory(models.Model):
    time = models.BigIntegerField(default=get_milliseconds)
    message = models.ForeignKey('Message', models.CASCADE, null=False)
    content = models.TextField(null=True, blank=True)
    giphy = URLField(null=True, blank=True)
Beispiel #29
0
class MusicAccess(Model):
    user_agent = TextField("Client's user agent", null = True)
    ip_address = CharField("Client's IP address", max_length = 45, null = True)
    referer = URLField("HTTP referer", null = True)
    music_id = IntegerField("Id accessed")
Beispiel #30
0
class Entry(models.Model):

    TYPE_TUTORIAL = 'tutorial'
    TYPE_PROJECT = 'project'
    TYPE_JUPYTER = 'jupyter'

    TYPE_CHOICES = (
        (TYPE_TUTORIAL, 'Tutorial'),
        (TYPE_PROJECT, 'Project'),
        (TYPE_JUPYTER, 'Jupyter Notebook')
    )

    ICON_MAP = {
        TYPE_TUTORIAL: '<i class="fa fa-graduation-cap"></i>',
        TYPE_PROJECT: '<i class="fa fa-bolt"></i>',
        TYPE_JUPYTER: '<i class="fa fa-code"></i>',
    }

    type = CharField(max_length=10,
                     choices=TYPE_CHOICES)
    title = CharField(max_length=250,
                      help_text='The main title of the entry. Does not have to be unique')
    subtitle = CharField(max_length=250, default='', blank=True)
    description = CharField(max_length=200, default='', blank=True)
    author = ForeignKey(User, on_delete=models.CASCADE, default=1, related_name='tutorials')
    thumbnail = FilerImageField(related_name="tutorial_thumbnail", on_delete=models.CASCADE, null=True)

    slug = SlugField(max_length=250, default='auto', unique=True)

    content = TextField(default='')
    text = TextField(default='')

    publishing_date = DateTimeField(default=timezone.now)
    creation_date = DateTimeField(default=timezone.now)

    next = URLField(null=True, blank=True)
    previous = URLField(null=True, blank=True)

    comments = GenericRelation(Comment)

    def save(self, *args, **kwargs) -> None:
        if self.slug == 'auto':
            self.slug = slugify(self.title)

        # So we need the "text" property to literally just contain the content of the post in all lower case and
        # without all the html markup (this will be used for fulltext search of keywords). BeautifulSoup does this
        # really well natively.
        soup = BeautifulSoup(self.content, 'lxml')
        self.text = soup.text.lower()

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

    @classmethod
    def get_most_recent(cls, n: int) -> List[Entry]:

        entries = cls.objects.order_by('-publishing_date').exclude(publishing_date__gte=timezone.now()).all()[0:n]

        return entries

    @property
    def comment_count(self):
        return len(self.comments.filter(active=True))

    @property
    def fa_icon(self):
        return self.ICON_MAP[self.type]

    @property
    def url(self) -> str:
        """
        Returns the absolute URL of the detail view of the entry instance.

        :return:
        """
        # This is a bit hacky (because it technically stretches the limits of SOC a bit) but very convenient!
        # Here is the thing: This is an abstract base model which will be the base for multiple specific
        # implementations, but we want a common list view for those and a list view would need knowledge of the urls
        # of the detail pages to link to those correctly. Thus we need a generalized method for getting those aka
        # we cannot do the {% url "..." %} thing because for that we need to provide a *specific* model type, which we
        # generally do not know at that point since it could be any specific implementation. Sooo it would be better if
        # the url information for the detail page would be attached to every individual element right away <- this
        # property.
        # Now this only works because of an implicit assumption we make: In the "url.py" module we set the name of
        # the according detail view for a model to the "type" property of the corresponding model class. If we adhere
        # to this convention, we can make use of it here and already assemble all the information to let django reverse
        # the url for a specific Entry instance...
        view_name = f'{BlogAppConfig.name}:{self.type}'
        return reverse_lazy(view_name, kwargs={'slug': self.slug})

    def __str__(self):
        return f'{self.type.upper()}: {self.title}'