def test_markdownfield_widget_instance():
    field = MarkdownField()
    widget_instance = MarkdownTextarea(attrs={'rows': 30, 'autofocus': True})
    form_field = field.formfield(widget=widget_instance)
    assert isinstance(form_field, MarkdownFormField)
    assert isinstance(form_field.widget, MarkdownTextarea)
    assert form_field.widget.attrs['rows'] == 30
    assert form_field.widget.attrs['autofocus'] is True
Example #2
0
class CollectionItem(models.Model):
    content_type = models.ForeignKey(ContentType,
                                     models.CASCADE,
                                     limit_choices_to=model_choices)
    object_id = models.PositiveIntegerField(
        help_text='Numeric id of the object.')
    content_object = GenericForeignKey('content_type', 'object_id')
    collection = models.ForeignKey('website.Collection',
                                   models.CASCADE,
                                   related_name='items')
    order = models.PositiveIntegerField(blank=True, null=True)
    description = MarkdownField(blank=True,
                                help_text='Teaser/description. Keep it short.')
    description_rendered = models.TextField(blank=True, editable=False)

    class Meta:
        ordering = ['collection_id', 'order']

    def __str__(self):
        return '{} {}: "{}"'.format(self.content_type.model.title(),
                                    self.object_id, str(self.content_object))

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        super(CollectionItem, self).save(*args, **kwargs)
Example #3
0
class Person(Publishable):
    """Describes a person"""
    identifier = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
    # Name info
    given_name = models.CharField('First name', max_length=100, help_text="A person's given or 'first' name(s).")
    additional_name = models.CharField('Middle name', blank=True, max_length=100, help_text="An additional name for a person, \
                                                                              such as a 'middle' name.")
    family_name = models.CharField('Last name', blank=True, max_length=140, help_text="A person's family or 'last' name(s).")

    image = FilerImageField(blank=True, null=True, help_text='Preferably a portrait/"head shot".')

    # Biographical Info
    description = MarkdownField('Bio/Description', blank=True)
    description_rendered = models.TextField(blank=True, editable=False)
    citizenships = models.ManyToManyField('locations.Country', blank=True)

    birth_year = models.PositiveSmallIntegerField(blank=True, null=True)
    birth_month = models.PositiveSmallIntegerField(blank=True, null=True)
    birth_day = models.PositiveSmallIntegerField(blank=True, null=True)

    # Notes
    notes = MarkdownField(blank=True)

    # Relations
    events = models.ManyToManyField('Event', blank=True)

    class Meta:
        ordering = ['family_name', 'given_name', 'additional_name']
        verbose_name_plural = 'people'

    def __str__(self):
        return " ".join((self.given_name, self.family_name))

    def full_display_name(self):
        name_parts = (self.given_name, self.additional_name or None, self.family_name)
        return " ".join([x for x in name_parts if x])
    full_display_name.short_description = "Full name"

    def get_absolute_url(self):
        return reverse('facts:person-detail', kwargs={
            'slug': slugify(self.full_display_name()),
            'identifier': str(self.identifier)
        })

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        super(Person, self).save(*args, **kwargs)
Example #4
0
class LegalTextVersion(models.Model):
    legaltext = models.ForeignKey(LegalText,
                                  verbose_name=_('Legal text'),
                                  on_delete=models.CASCADE)
    valid_from = models.DateTimeField(_('Valid from'), default=timezone.now)

    content = MarkdownField(
        _('Text'),
        help_text=_(
            'You can use [block:foo]Your text[/block] to create a block with an anchor. '
            'Anchors ([anchor:foo]) can be used in checkbox texts to link to '
            'specific parts of the legal text.'))

    class Meta:
        verbose_name = _('Legal text version')
        verbose_name_plural = _('Legal text versions')
        ordering = ('legaltext__slug', '-valid_from')

    def __str__(self):
        return '{0} ({1:%x %X})'.format(self.legaltext.name,
                                        timezone.localtime(self.valid_from))

    @property
    def name(self):
        return self.legaltext.name

    def render_content(self):
        anchor_class = getattr(settings, 'LEGALTEXT_ANCHOR_CLASS', None)

        def block_nl_callback(match):
            return '\n\n{0}\n\n'.format(match.group(1))

        def block_open_callback(match):
            block_open_callback.count += 1
            return ('<div class="legaltext-block legaltext-block-{0}">'
                    '<span id="{0}"{1}></span>').format(
                        match.group(1),
                        ' class="{0}"'.format(anchor_class)
                        if anchor_class else '',
                    )

        block_open_callback.count = 0

        def block_close_callback(match):
            block_close_callback.count += 1
            return '</div>'

        block_close_callback.count = 0

        content = BLOCK_OPEN_NL_RE.sub(block_nl_callback, self.content)
        content = BLOCK_CLOSE_NL_RE.sub(block_nl_callback, content)

        content = render_markdown(content)
        content = BLOCK_OPEN_RE.sub(block_open_callback, content)
        content = BLOCK_CLOSE_RE.sub(block_close_callback, content)

        if block_open_callback.count == block_close_callback.count:
            return content
        return render_markdown(self.content)
Example #5
0
class Event(Publishable):
    """Describes an event, one which may have a start and end date"""
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=110, allow_unicode=True, unique=True)
    event_type = models.ForeignKey('EventType', models.SET_NULL,
                                   verbose_name='type',
                                   blank=True, null=True)
    description = MarkdownField(blank=True)
    description_rendered = models.TextField(blank=True, editable=False)
    start_year = models.PositiveSmallIntegerField(blank=True, null=True)
    start_month = models.PositiveSmallIntegerField(blank=True, null=True)
    start_day = models.PositiveSmallIntegerField(blank=True, null=True)

    @property
    def fuzzy_start_date(self):
        return fuzzydate(self.start_year, self.start_month, self.start_day)

    end_year = models.PositiveSmallIntegerField(blank=True, null=True)
    end_month = models.PositiveSmallIntegerField(blank=True, null=True)
    end_day = models.PositiveSmallIntegerField(blank=True, null=True)

    @property
    def fuzzy_end_date(self):
        return fuzzydate(self.end_year, self.end_month, self.end_day)

    places = models.ManyToManyField('locations.Place', blank=True)
    documents = models.ManyToManyField('sources.Document', blank=True)
    notes = MarkdownField(blank=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('facts:event-detail', args=[self.slug])

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        if not self.slug or self.slug == '':
            self.slug = slugify(self.name, allow_unicode=True)
        super(Event, self).save(*args, **kwargs)

    class Meta:
        ordering = ['created_at']
Example #6
0
class Post(models.Model):

    content = MarkdownField(_('Content'))

    class Meta:
        verbose_name = _('Post')
        verbose_name_plural = _('Posts')

    def __unicode__(self):
        return u'{0}'.format(self.id)
Example #7
0
class LegalTextCheckbox(models.Model):
    legaltext_version = models.ForeignKey(LegalTextVersion,
                                          verbose_name=_('Legal text version'),
                                          related_name='checkboxes',
                                          on_delete=models.CASCADE)

    content = MarkdownField(
        _('Text'),
        help_text=
        _('You can use [anchor]Your text[/anchor] to create a link to the full legal text. '
          'If you use [anchor:foo]Your text[/anchor] the link will go to the block "foo" '
          'inside the legal text.'))
    order = models.PositiveIntegerField(_('Order'), blank=True, null=True)

    class Meta:
        verbose_name = _('Legal text checkbox')
        verbose_name_plural = _('Legal text Checkboxes')
        ordering = ('legaltext_version', 'order')
        unique_together = (('legaltext_version', 'order'), )

    def __str__(self):
        return gettext('Checkbox for {0} ({1})').format(
            self.legaltext_version.name, '{0:%x %X}'.format(
                timezone.localtime(self.legaltext_version.valid_from)))

    def render_content(self):
        def anchor_callback(match):
            return '<a href="{0}{1}" class="legaltext-anchor" target="_blank">{2}</a>'.format(
                self.legaltext_version.legaltext.get_absolute_url(),
                '#{0}'.format(match.group(1)) if match.group(1) else '',
                match.group(2))

        content = ANCHOR_RE.sub(
            anchor_callback,
            normalize_newlines(self.content).replace('\n', '<br />'))
        return render_markdown(content).replace('<p>', '').replace('</p>', '')

    def save(self, *args, **kwargs):
        if not self.order:
            self.order = (self.legaltext_version.checkboxes.aggregate(
                next_order=models.Max('order'))['next_order'] or 0) + 1
        super().save(*args, **kwargs)
Example #8
0
class Entry(Publishable):
    """An entry in a 'blog' or whatever you want to call it."""
    title = models.CharField(max_length=100)
    subtitle = models.CharField(max_length=100, blank=True)
    slug = models.SlugField(max_length=110, allow_unicode=True, unique=True)
    author = models.CharField('Author(s)', blank=True, max_length=100)

    content = MarkdownField(blank=True)
    content_rendered = models.TextField(blank=True, editable=False)
    description = MarkdownField(
        'Summary/Description',
        blank=True,
        help_text='Short text to be used where post might be promoted/referenced. Limited to 400 characters.'
    )
    description_rendered = models.TextField(blank=True, editable=False)
    share_text = models.CharField(blank=True, max_length=140)
    featured_image = FilerImageField(blank=True, null=True)

    is_sponsored = models.BooleanField(default=False)
    sponsored_logo = FilerImageField(blank=True, null=True, related_name='sponsored_article')

    publication_date = models.DateTimeField(
        blank=True,
        null=True,
        help_text="""<p>Publication date will be set to the current time automatically, when <em>published</em> is selected.
        <p>You may set a date/time manually, but <strong>you must
            select <em>published</em> for the post to appear!</strong>
        """
    )

    categories = models.ManyToManyField(
        Category,
        blank=True,
        related_name='entries',
    )
    tags = TaggableManager(blank=True)
    related_entries = models.ManyToManyField('self', blank=True)

    class Meta:
        ordering = ("-publication_date", "-created_at")
        get_latest_by = "publication_date"
        verbose_name = "entry"
        verbose_name_plural = "entries"

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if self.published and not self.publication_date:
            self.publication_date = timezone.now()
        self.content_rendered = render_markdown(self.content)
        self.description_rendered = render_markdown(self.description)
        super(Entry, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse(
            'writings:entry-detail',
            kwargs={
                'slug': self.slug,
            }
        )

    def is_visible(self):
        return self.published and self.publication_date <= timezone.now()

    def get_next_published_entry(self):
        if not self.publication_date:
            return None  # If no publication date
        query = Q(publication_date__gt=self.publication_date)
        query |= Q(publication_date=self.publication_date, pk__gt=self.pk)
        qs = self.__class__.objects.published().filter(query).order_by('publication_date', 'pk')
        try:
            return qs[0]
        except IndexError:
            return None

    def get_previous_published_entry(self):
        if not self.publication_date:
            return None  # If no publication date
        query = Q(publication_date__lt=self.publication_date)
        query |= Q(publication_date=self.publication_date, pk__lt=self.pk)
        qs = self.__class__.objects.published().filter(query).order_by('-publication_date', '-pk')
        try:
            return qs[0]
        except IndexError:
            return None
Example #9
0
class Organization(MPTTModel, Publishable):
    """Abstract base model for organizations"""

    identifier = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=110, allow_unicode=True)
    countries = models.ManyToManyField('locations.Country', blank=True)
    leaders = models.ManyToManyField('Person', blank=True,
                                     related_name='organizations_led')
    initiatives = models.ManyToManyField('infrastructure.Initiative', blank=True)
    headquarters = models.ForeignKey('locations.Place', models.SET_NULL, blank=True, null=True)

    description = MarkdownField(blank=True)
    description_rendered = models.TextField(blank=True, editable=False)

    notes = MarkdownField(blank=True)
    related_events = models.ManyToManyField('Event', blank=True)
    founding_year = models.PositiveSmallIntegerField(blank=True, null=True)
    founding_month = models.PositiveSmallIntegerField(blank=True, null=True)
    founding_day = models.PositiveSmallIntegerField(blank=True, null=True)

    @property
    def fuzzy_founding_date(self):
        return fuzzydate(self.founding_year, self.founding_month, self.founding_day)

    dissolution_year = models.PositiveSmallIntegerField(blank=True, null=True)
    dissolution_month = models.PositiveSmallIntegerField(blank=True, null=True)
    dissolution_day = models.PositiveSmallIntegerField(blank=True, null=True)

    @property
    def fuzzy_dissolution_date(self):
        return fuzzydate(self.dissolution_year, self.dissolution_month, self.dissolution_day)

    parent = TreeForeignKey('self', models.CASCADE,
                            null=True, blank=True,
                            verbose_name='parent organization',
                            related_name='children', db_index=True)
    staff_size = models.PositiveIntegerField("Staff/Personnel count",
                                             blank=True, null=True)
    mission = MarkdownField("Mandate/Mission Statement", blank=True)
    mission_rendered = models.TextField(blank=True, editable=False)
    related_organizations = models.ManyToManyField('self', blank=True)

    documents = models.ManyToManyField('sources.Document', blank=True)

    publishable_objects = PublishableQuerySet.as_manager()

    class MPTTMeta:
            order_insertion_by = ['name']

    class Meta:
        verbose_name_plural = "all organizations"
        ordering = ['name', 'created_at']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('facts:organization-detail', kwargs={
            'slug': self.slug,
            'identifier': str(self.identifier)
        })

    def get_detail_types(self):
        return {
            model_name: label
            for model_name, label in DETAIL_MODEL_NAMES.items()
            if hasattr(self, model_name)
        }

    def get_organization_types(self):
        return frozenset([
            label
            for model_name, label in DETAIL_MODEL_NAMES.items()
            if hasattr(self, model_name)
        ])

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        self.mission_rendered = render_markdown(self.mission)
        if not self.slug or self.slug == '':
            self.slug = slugify(self.name, allow_unicode=True)
        super(Organization, self).save(*args, **kwargs)
def test_markdownfield_formfield():
    field = MarkdownField()
    form_field = field.formfield()
    assert isinstance(form_field, MarkdownFormField)
    assert isinstance(form_field.widget, MarkdownTextarea)
Example #11
0
class Project(Publishable):
    """Describes a project"""
    identifier = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
    name = models.CharField("Project name/title", max_length=300)
    slug = models.SlugField(max_length=310, allow_unicode=True)
    alternate_name = models.CharField(
        blank=True,
        max_length=100,
        help_text='Alternate name for project, suitable for display as a header'
    )
    alternate_slug = models.SlugField(
        blank=True,
        max_length=110,
        allow_unicode=True
    )
    description = MarkdownField(blank=True)
    description_rendered = models.TextField(blank=True, editable=False)

    countries = models.ManyToManyField('locations.Country', blank=True)
    regions = models.ManyToManyField(
        'locations.Region',
        blank=True,
        help_text='Select or create geographic region names.'
    )
    infrastructure_type = models.ForeignKey(
        InfrastructureType,
        models.SET_NULL, blank=True, null=True,
        help_text='Select or create named infrastructure types.'
    )
    total_cost = models.BigIntegerField(
        blank=True, null=True,
        help_text="Values in whole units (dollars, etc.)"
    )
    total_cost_currency = models.CharField(
        blank=True, null=True,
        max_length=3,
        choices=CURRENCY_CHOICES,
        default=DEFAULT_CURRENCY_CHOICE
    )

    start_year = models.PositiveSmallIntegerField(blank=True, null=True)
    start_month = models.PositiveSmallIntegerField(blank=True, null=True)
    start_day = models.PositiveSmallIntegerField(blank=True, null=True)

    @property
    def fuzzy_start_date(self):
        return fuzzydate(self.start_year, self.start_month, self.start_day)

    commencement_year = models.PositiveSmallIntegerField('Year of commencement of works', blank=True, null=True)
    commencement_month = models.PositiveSmallIntegerField('Month of commencement of works', blank=True, null=True)
    commencement_day = models.PositiveSmallIntegerField('Day of commencement of works', blank=True, null=True)

    @property
    def fuzzy_commencement_date(self):
        return fuzzydate(self.commencement_year, self.commencement_month, self.commencement_day)

    planned_completion_year = models.PositiveSmallIntegerField(blank=True, null=True)
    planned_completion_month = models.PositiveSmallIntegerField(blank=True, null=True)
    planned_completion_day = models.PositiveSmallIntegerField(blank=True, null=True)

    @property
    def fuzzy_planned_completion_date(self):
        return fuzzydate(self.planned_completion_year, self.planned_completion_month, self.planned_completion_day)

    status = models.PositiveSmallIntegerField(
        blank=True, null=True,
        choices=ProjectStatus.STATUSES, default=ProjectStatus.ANNOUNCED
    )
    new = models.NullBooleanField('New Construction?')
    initiatives = models.ManyToManyField('Initiative', blank=True)
    documents = models.ManyToManyField('ProjectDocument', blank=True)
    sources = ArrayField(
        models.CharField(max_length=1000, validators=[URLLikeValidator]),
        blank=True,
        null=True,
        default=list,
        verbose_name="Sources URLs",
        help_text='Enter URLs separated by commas.'
    )
    notes = MarkdownField(blank=True)
    # Organization relations
    contractors = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Contractors',
        related_name='projects_contracted',
        blank=True
    )
    consultants = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Consultants',
        related_name='projects_consulted',
        blank=True
    )
    implementers = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Client or implementing agency/ies',
        related_name='projects_implemented',
        blank=True
    )
    operators = models.ManyToManyField(
        'facts.Organization',
        related_name='projects_operated',
        blank=True,
    )
    # Person relations
    contacts = models.ManyToManyField(
        'facts.Person',
        verbose_name='Points of contact',
        related_name='projects_contacts',
        blank=True
    )

    # Extras & Internal Use
    extra_data = models.ManyToManyField('facts.Data', blank=True)
    verified_path = models.NullBooleanField(blank=True)
    collection_stage = models.PositiveSmallIntegerField(
        blank=True, null=True,
        choices=CollectionStage.STAGES,
        default=CollectionStage.IDENTIFIED
    )

    # Geodata
    geo = models.ForeignKey(
        'locations.GeometryStore',
        models.SET_NULL,
        blank=True, null=True,
        related_name='projects'
    )

    class Meta:
        ordering = ['name']

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        super(Project, self).save(*args, **kwargs)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse(
            'infrastructure:project-detail',
            kwargs={
                'slug': self.alternate_slug or self.slug or 'p',
                'identifier': str(self.identifier)
            }
        )
Example #12
0
class ProjectDocument(models.Model):
    DOCUMENT_TYPES = (
        ('Public Materials', (
            (1, 'Press Releases'),
            (2, 'Presentations & Brochures'),
            (3, 'National Development Plans'),
        )),
        ('Agreements/Contracts', (
            (4, 'MoU'),
            (5, 'Financing Agreements'),
            (6, 'Procurement Contracts'),
            (7, 'Other Agreements'),
        )),
        ('Operational Documents', (
            (8, 'Concept Notes'),
            (9, 'Review and Approval Documents'),
            (10, 'Procurement Documents'),
            (11, 'Appraisal Documents'),
            (12, 'Administration Manuals'),
            (13, 'Aide-Memoires'),
            (14, 'Financial Audits'),
        )),
        ('Impact Assessment and Monitoring Reports', (
            (15, 'Environmental and Social Assessment'),
            (16, 'Resettlement Frameworks'),
            (17, 'Safeguards Monitoring Reports'),
            (18, 'Consultation Minutes'),
        )),
        ('Implementation Progress Reports', (
            (19, 'Progress Reports'),
            (20, 'Completion Reports'),
        )),
        ('Miscellaneous Reports', (
            (21, 'Miscellaneous Reports'),
        )),
        ('Unofficial Sources', (
            (22, 'Unofficial Sources'),
        )),
    )

    identifier = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
    document = models.ForeignKey(
        'sources.Document',
        models.SET_NULL,
        blank=True,
        null=True
    )
    source_url = models.CharField(blank=True, max_length=1000, validators=[URLLikeValidator])
    document_type = models.PositiveSmallIntegerField(
        'type',
        choices=DOCUMENT_TYPES,
        blank=True, null=True
    )
    notes = MarkdownField(blank=True)
    status_indicator = models.PositiveSmallIntegerField(
        blank=True, null=True,
        choices=ProjectStatus.STATUSES
    )

    class Meta:
        ordering = ['document_type', 'source_url']

    def __str__(self):
        if self.source_url:
            return self.source_url
        return "Document #{}".format(self.id)

    def get_source_url_tail(self):
        return self.source_url.split('/')[-1] or None

    @classmethod
    def _flattened_doc_types(cls):
        return (value for _, subset in cls.DOCUMENT_TYPES for value in subset)

    @classmethod
    def get_document_type_names(cls):
        return tuple(name for _, name in cls._flattened_doc_types())

    @classmethod
    def lookup_document_type_by_name(cls, name):
        if name:
            filtered = filter(lambda x: x[1].lower() == name.lower(), cls._flattened_doc_types())
            as_list = list(filtered)
            if len(as_list) == 1:
                return as_list[0]
        return None
Example #13
0
class PowerPlant(Publishable):
    """Describes a Power Plant"""

    name = models.CharField(max_length=140)
    slug = models.SlugField(max_length=150, allow_unicode=True)

    description = MarkdownField(blank=True)
    description_rendered = models.TextField(blank=True, editable=False)

    infrastructure_type = models.ForeignKey(
        InfrastructureType,
        models.SET_NULL,
        blank=True,
        null=True,
        help_text='Select or create named insfrastructure types.',
    )
    fuels = models.ManyToManyField('Fuel', blank=True)
    total_cost = models.BigIntegerField(
        blank=True,
        null=True,
        help_text="Values in whole units (dollars, etc.)")
    total_cost_currency = models.CharField(blank=True,
                                           max_length=3,
                                           choices=CURRENCY_CHOICES,
                                           default=DEFAULT_CURRENCY_CHOICE)
    countries = models.ManyToManyField('locations.Country', blank=True)
    regions = models.ManyToManyField(
        'locations.Region',
        blank=True,
        help_text='Select or create geographic region names.')
    status = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=PowerPlantStatus.STATUSES)
    plant_year_online = models.PositiveSmallIntegerField(blank=True, null=True)
    plant_month_online = models.PositiveSmallIntegerField(blank=True,
                                                          null=True)
    plant_day_online = models.PositiveSmallIntegerField(blank=True, null=True)

    plant_initiatives = models.ManyToManyField('Initiative', blank=True)

    @property
    def fuzzy_plant_online_date(self):
        return fuzzydate(self.plant_year_online, self.plant_month_online,
                         self.plant_day_online)

    decommissioning_year = models.PositiveSmallIntegerField(blank=True,
                                                            null=True)
    decommissioning_month = models.PositiveSmallIntegerField(blank=True,
                                                             null=True)
    decommissioning_day = models.PositiveSmallIntegerField(blank=True,
                                                           null=True)

    @property
    def fuzzy_decommissioning_date(self):
        return fuzzydate(self.decommissioning_year, self.decommissioning_month,
                         self.decommissioning_day)

    plant_capacity = models.FloatField(blank=True, null=True)

    plant_capacity_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)

    plant_output = models.FloatField(blank=True, null=True)

    plant_output_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)

    plant_output_year = models.PositiveSmallIntegerField(blank=True, null=True)

    estimated_plant_output = models.FloatField(blank=True, null=True)
    estimated_plant_output_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)

    plant_CO2_emissions = models.FloatField(blank=True, null=True)

    plant_CO2_emissions_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)

    grid_connected = models.NullBooleanField('Grid connected?')
    notes = MarkdownField(blank=True)

    # Geodata
    geo = models.ForeignKey(
        'locations.GeometryStore',
        models.SET_NULL,
        blank=True,
        null=True,
        related_name='power_plants',
    )

    operators = models.ManyToManyField('facts.Organization',
                                       verbose_name='Operators',
                                       related_name='plants_operated',
                                       blank=True)

    sources = ArrayField(
        models.CharField(max_length=1000, validators=[URLLikeValidator]),
        blank=True,
        null=True,
        default=list,
        verbose_name="Sources URLs",
        help_text='Enter URLs separated by commas.',
    )

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('infrastructure:powerplant-detail',
                       kwargs={'slug': self.slug})

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        return super().save(*args, **kwargs)
Example #14
0
def test_markdownfield_formfield():
    field = MarkdownField()
    form_field = field.formfield()
    assert isinstance(form_field, MarkdownFormField)
    assert isinstance(form_field.widget, MarkdownTextarea)
Example #15
0
def test_markdownfield_formfield_no_override():
    field = MarkdownField()
    form_field = field.formfield(widget=CustomMarkdownTextarea)
    assert isinstance(form_field, MarkdownFormField)
    assert isinstance(form_field.widget, CustomMarkdownTextarea)
Example #16
0
class Initiative(MPTTModel, Publishable):
    """Describes an initiative"""

    identifier = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
    name = models.CharField(max_length=140)
    slug = models.SlugField(max_length=150, allow_unicode=True)
    initiative_type = models.ForeignKey('InitiativeType', models.SET_NULL, blank=True, null=True)
    notes = MarkdownField(blank=True)
    principal_agent = models.ForeignKey(
        'facts.Organization', models.SET_NULL, blank=True, null=True,
        related_name='principal_initiatives',
    )
    parent = TreeForeignKey('self', null=True, blank=True,
                            verbose_name='parent initiative',
                            related_name='children', db_index=True)
    related_initiatives = models.ManyToManyField('self', blank=True)

    documents = models.ManyToManyField('sources.Document', blank=True)

    founding_year = models.PositiveSmallIntegerField('Founding/Signing Year', blank=True, null=True)
    founding_month = models.PositiveSmallIntegerField('Founding/Signing Month', blank=True, null=True)
    founding_day = models.PositiveSmallIntegerField('Founding/Signing Day', blank=True, null=True)

    @property
    def fuzzy_founding_date(self):
        return fuzzydate(self.founding_year, self.founding_month, self.founding_day)

    affiliated_organizations = models.ManyToManyField('facts.Organization', blank=True)
    affiliated_events = models.ManyToManyField('facts.Event', blank=True)
    affiliated_people = models.ManyToManyField('facts.Person', blank=True)
    member_countries = models.ManyToManyField(
        'locations.Country', blank=True, related_name='initiatives_joined'
    )
    geographic_scope = models.ManyToManyField(
        'locations.Country', blank=True, related_name='initiatives_in_scope'
    )

    appeared_year = models.PositiveSmallIntegerField('First Apperance Year', blank=True, null=True)
    appeared_month = models.PositiveSmallIntegerField('First Apperance Month', blank=True, null=True)
    appeared_day = models.PositiveSmallIntegerField('First Apperance Day', blank=True, null=True)

    @property
    def fuzzy_appeared_date(self):
        return fuzzydate(self.appeared_year, self.appeared_month, self.appeared_day)

    class Meta:
        ordering = ['name']

    publishable_objects = PublishableQuerySet.as_manager()

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug or self.slug == '':
            self.slug = slugify(self.name, allow_unicode=True)
        super(Initiative, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse(
            'infrastructure:initiative-detail',
            kwargs={
                'slug': self.slug or 'i',
                'identifier': str(self.identifier)
            }
        )
Example #17
0
class Project(Publishable):
    """Describes a project"""

    # ---- STANDARD FIELDS ---- #
    identifier = models.UUIDField(default=uuid.uuid4,
                                  unique=True,
                                  editable=False)
    name = models.CharField("Project name/title", max_length=300)
    slug = models.SlugField(max_length=310, allow_unicode=True)
    alternate_name = models.CharField(
        blank=True,
        max_length=100,
        help_text=
        'Alternate name for project, suitable for display as a header',
    )
    alternate_slug = models.SlugField(blank=True,
                                      max_length=110,
                                      allow_unicode=True)
    description = MarkdownField(blank=True)
    description_rendered = models.TextField(blank=True, editable=False)

    countries = models.ManyToManyField('locations.Country', blank=True)
    regions = models.ManyToManyField(
        'locations.Region',
        blank=True,
        help_text='Select or create geographic region names.')
    infrastructure_type = models.ForeignKey(
        InfrastructureType,
        models.SET_NULL,
        blank=True,
        null=True,
        help_text='Select or create named infrastructure types.',
    )
    total_cost = models.BigIntegerField(
        blank=True,
        null=True,
        help_text="Values in whole units (dollars, etc.)")
    total_cost_currency = models.CharField(
        blank=True,
        null=True,
        max_length=3,
        choices=CURRENCY_CHOICES,
        default=DEFAULT_CURRENCY_CHOICE,
    )

    start_year = models.PositiveSmallIntegerField(blank=True, null=True)
    start_month = models.PositiveSmallIntegerField(blank=True, null=True)
    start_day = models.PositiveSmallIntegerField(blank=True, null=True)
    commencement_year = models.PositiveSmallIntegerField(
        'Year of commencement of works', blank=True, null=True)
    commencement_month = models.PositiveSmallIntegerField(
        'Month of commencement of works', blank=True, null=True)
    commencement_day = models.PositiveSmallIntegerField(
        'Day of commencement of works', blank=True, null=True)
    planned_completion_year = models.PositiveSmallIntegerField(blank=True,
                                                               null=True)
    planned_completion_month = models.PositiveSmallIntegerField(blank=True,
                                                                null=True)
    planned_completion_day = models.PositiveSmallIntegerField(blank=True,
                                                              null=True)
    linear_length = models.PositiveSmallIntegerField(blank=True,
                                                     null=True,
                                                     help_text="km")
    new = models.NullBooleanField('New Construction?')
    initiatives = models.ManyToManyField('Initiative', blank=True)
    documents = models.ManyToManyField('ProjectDocument', blank=True)
    sources = ArrayField(
        models.CharField(max_length=1000, validators=[URLLikeValidator]),
        blank=True,
        null=True,
        default=list,
        verbose_name="Sources URLs",
        help_text='Enter URLs separated by commas.',
    )
    notes = MarkdownField(blank=True)

    # Organization relations
    contractors = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Contractors',
        related_name='projects_contracted',
        blank=True,
    )
    manufacturers = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Manufacturers',
        related_name='projects_manufactured',
        blank=True,
    )
    consultants = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Consultants',
        related_name='projects_consulted',
        blank=True,
    )
    implementers = models.ManyToManyField(
        'facts.Organization',
        verbose_name='Client or implementing agency/ies',
        related_name='projects_implemented',
        blank=True,
    )
    operators = models.ManyToManyField('facts.Organization',
                                       related_name='projects_operated',
                                       blank=True)
    # Person relations
    contacts = models.ManyToManyField(
        'facts.Person',
        verbose_name='Points of contact',
        related_name='projects_contacts',
        blank=True,
    )

    # Extras & Internal Use
    extra_data = models.ManyToManyField('facts.Data', blank=True)
    verified_path = models.NullBooleanField(blank=True)
    collection_stage = models.PositiveSmallIntegerField(
        blank=True,
        null=True,
        choices=CollectionStage.STAGES,
        default=CollectionStage.IDENTIFIED)

    # Geodata
    geo = models.ForeignKey('locations.GeometryStore',
                            models.SET_NULL,
                            blank=True,
                            null=True,
                            related_name='projects')
    status = models.PositiveSmallIntegerField(blank=True,
                                              null=True,
                                              choices=ProjectStatus.STATUSES,
                                              default=ProjectStatus.ANNOUNCED)

    # ---- End STANDARD FIELDS ---- #

    # ---- POWER PLANT TYPE PROJECT FIELDS ---- #
    power_plant = models.ForeignKey('PowerPlant',
                                    models.CASCADE,
                                    blank=True,
                                    null=True)
    fuels = models.ManyToManyField('Fuel', blank=True)

    # These are ostensibly for all projects but they make the most sense
    # for power plants
    project_output = models.FloatField(blank=True, null=True)

    project_output_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)

    project_output_year = models.PositiveSmallIntegerField(blank=True,
                                                           null=True)

    estimated_project_output = models.FloatField(blank=True, null=True)
    estimated_project_output_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)
    project_capacity = models.FloatField(blank=True, null=True)

    project_capacity_unit = models.CharField(
        blank=True,
        default='',
        max_length=20,
        choices=ProjectCapacityUnits.UNITS)

    project_capacity_timeframe = models.CharField(
        blank=True, max_length=10, choices=ProjectTimeFrameUnits.TIME_UNITS)

    project_CO2_emissions = models.FloatField(blank=True, null=True)

    project_CO2_emissions_unit = models.PositiveSmallIntegerField(
        blank=True, null=True, choices=ProjectPlantUnits.UNITS)

    nox_reduction_system = models.NullBooleanField('NOx Reduction System?')
    sox_reduction_system = models.NullBooleanField('SOx Reduction System?')

    # ---- END POWER PLANT TYPE PROJECT FIELDS ---- #

    # ---- TRANSMISSION TYPE PROJECT FIELDS ---- #
    design_voltage = models.BigIntegerField(null=True,
                                            blank=True,
                                            help_text="Design Voltage (kV)")
    direct_current = models.NullBooleanField(null=True,
                                             blank=True,
                                             help_text="Direct Current?")
    electricity_flow = models.CharField(
        null=True,
        blank=True,
        max_length=15,
        choices=(('bidirectional', 'Bidirectional'), ('unidirectional',
                                                      'Unidirectional')),
        help_text="Electricity Flow (direction)",
    )
    estimated_transfer_capacity = models.BigIntegerField(
        null=True, blank=True, help_text="Estimated Transfer Capacity (MW)")
    # ---- END TRANSMISSION TYPE PROJECT FIELDS ---- #

    # ---- PIPELINE TYPE PROJECT FIELDS ---- #
    pipeline_diameter = models.IntegerField("Pipeline Diameter",
                                            null=True,
                                            blank=True)
    pipeline_diameter_unit = models.CharField("Diameter Unit",
                                              blank=True,
                                              max_length=6,
                                              choices=PipelineDiameters.UNITS,
                                              help_text="Diameter unit")
    pipeline_metered = models.NullBooleanField("Pipeline Metered?",
                                               null=True,
                                               blank=True)

    pipeline_throughput = models.BigIntegerField("Throughput",
                                                 null=True,
                                                 blank=True)
    pipeline_throughput_unit = models.CharField(
        "Throughput Unit",
        blank=True,
        max_length=20,
        choices=ProjectThroughputUnits.UNITS)
    pipeline_throughput_timeframe = models.CharField(
        "Throughput Timeframe",
        blank=True,
        max_length=10,
        choices=ProjectTimeFrameUnits.TIME_UNITS)
    pipeline_throughput_year = models.PositiveSmallIntegerField(
        "Throughput Year", null=True, blank=True)

    # ---- END PIPELINE TYPE PROJECT FIELDS ---- #

    # ---- PROPERTIES ---- #
    @property
    def fuzzy_output_date(self):
        return fuzzydate(self.project_output_year)

    @property
    def fuzzy_start_date(self):
        return fuzzydate(self.start_year, self.start_month, self.start_day)

    @property
    def fuzzy_commencement_date(self):
        return fuzzydate(self.commencement_year, self.commencement_month,
                         self.commencement_day)

    @property
    def fuzzy_planned_completion_date(self):
        return fuzzydate(self.planned_completion_year,
                         self.planned_completion_month,
                         self.planned_completion_day)

    @property
    def humanize_capacity(self):
        if self.project_capacity is None:
            return False
        if self.project_capacity >= (10**
                                     6):  # Is the capacity GTE to 1 million
            return True
        return False

    @property
    def pipeline_capacity_property(self):
        if self.project_capacity is None:
            return None
        pc = ''
        if self.project_capacity_unit:
            pc += " {}".format(
                self.get_project_capacity_unit_display().lower())
        if self.project_capacity_timeframe:
            pc += " {}".format(self.get_project_capacity_timeframe_display())
        return pc

    @property
    def pipeline_throughput_property(self):
        if self.pipeline_throughput is None:
            return None
        pt = ''
        if self.pipeline_throughput_unit:
            pt += " {}".format(
                self.get_pipeline_throughput_unit_display().lower())
        if self.pipeline_throughput_timeframe:
            pt += " {}".format(
                self.get_pipeline_throughput_timeframe_display())
        if self.pipeline_throughput_year:
            pt += " ({})".format(self.pipeline_throughput_year)
        return pt

    # ---- END PROPERTIES ---- #

    class Meta:
        ordering = ['name']

    def save(self, *args, **kwargs):
        self.description_rendered = render_markdown(self.description)
        super(Project, self).save(*args, **kwargs)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse(
            'infrastructure:project-detail',
            kwargs={
                'slug': self.alternate_slug or self.slug or 'p',
                'identifier': str(self.identifier),
            },
        )