Skip to content

Commit

Permalink
Squashed merge of task/GH-93-GH-142-GH-133-article-list-plugins-and-s…
Browse files Browse the repository at this point in the history
…tyles--no-reverts of the following:

commit a854b0b
Merge: df7a458 82ffc16
Author: Wesley Bomar <[email protected]>
Date:   Fri Nov 12 17:35:44 2021 -0600

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit df7a458
Author: Wesley Bomar <[email protected]>
Date:   Fri Nov 12 17:35:31 2021 -0600

    Quick: Submod update for GH-93, GH-142, GH-133

commit 7245196
Merge: 92b234e b9d08f8
Author: Wesley Bomar <[email protected]>
Date:   Thu Nov 4 12:02:30 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 92b234e
Merge: d452772 4838e7e
Author: Wesley Bomar <[email protected]>
Date:   Thu Oct 14 16:31:54 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit d452772
Author: Wesley Bomar <[email protected]>
Date:   Thu Oct 7 16:59:43 2021 -0500

    GH-93: Fix bug from intro of `x-overlay--` mixin

    Bug Source:
    - #368
        - #361
            - TACC/Core-CMS-Resources@6d253e1...522c296#diff-5894bbc

commit 17d5174
Author: Wesley Bomar <[email protected]>
Date:   Thu Oct 7 13:30:24 2021 -0500

    Major: Deprecate `.x-overlay--` classes

    Affects Frontera and UTRC. Both are updated in this commit.

commit 9525e25
Author: Wesley Bomar <[email protected]>
Date:   Thu Oct 7 13:18:53 2021 -0500

    GH-93: Fix: Do NOT load migrate CSS on homepage

commit 23abf1d
Author: Wesley Bomar <[email protected]>
Date:   Thu Oct 7 12:54:04 2021 -0500

    GH-93: Frontera homepage banner fixes/improvements

commit 7ffbd47
Merge: 265fec0 666bf95
Author: Wesley Bomar <[email protected]>
Date:   Thu Oct 7 12:32:14 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 265fec0
Merge: fc21621 c117ee6
Author: Wesley Bomar <[email protected]>
Date:   Tue Sep 28 17:01:07 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit fc21621
Author: Wesley Bomar <[email protected]>
Date:   Tue Sep 28 17:00:43 2021 -0500

    GH-93-ETC: Update submod to have its latest main

commit cb9c1a1
Merge: c4186df 1248117
Author: Wesley Bomar <[email protected]>
Date:   Thu Sep 2 14:24:54 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit c4186df
Author: Wesley Bomar <[email protected]>
Date:   Wed Sep 1 16:22:57 2021 -0500

    GH-93/GH-142/GH-133: Remove errant submod commits

commit 7563f7c
Merge: 579f5c6 97f7df0
Author: Wesley Bomar <[email protected]>
Date:   Tue Aug 31 13:59:51 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 579f5c6
Author: Wesley Bomar <[email protected]>
Date:   Mon Aug 23 20:25:31 2021 -0500

    Docs: Corrections to "How to Extend Plugin" doc

commit 3bdde39
Merge: 266a9ad 1d50a7b
Author: Wesley Bomar <[email protected]>
Date:   Mon Aug 16 18:18:22 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 266a9ad
Merge: 647d394 a66033a
Author: Wesley Bomar <[email protected]>
Date:   Mon Aug 16 18:09:17 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 647d394
Merge: dcf606c ac6d873
Author: Wesley Bomar <[email protected]>
Date:   Mon Aug 16 17:19:26 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit dcf606c
Merge: 74b9a9c e0e420d
Author: Wesley Bomar <[email protected]>
Date:   Mon Aug 16 17:04:52 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 74b9a9c
Author: Wesley Bomar <[email protected]>
Date:   Fri Aug 13 05:52:08 2021 -0500

    GH-93: Avoid title color bug with upcoming PR #312

    Ensure heading turns white.

commit 1729430
Author: Wesley Bomar <[email protected]>
Date:   Fri Jul 30 13:43:29 2021 -0500

    GH-142, GH-133: Article List Plugin Helpers

    This code was lost during re-creation:
    - of #264
    - as #280.

commit eea0768
Merge: 89b1136 374b78e
Author: Wesley Bomar <[email protected]>
Date:   Fri Jul 30 12:46:27 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 89b1136
Author: Wesley Bomar <[email protected]>
Date:   Tue Jul 20 17:24:37 2021 -0500

    GH-93: Frontera: Plugin-less style … — Real Fix

commit 5bd6484
Author: Wesley Bomar <[email protected]>
Date:   Tue Jul 20 17:23:30 2021 -0500

    GH-93: Frontera: Plugin-less style … snippet — Fix

commit f6b8f3a
Author: Wesley Bomar <[email protected]>
Date:   Tue Jul 20 17:03:17 2021 -0500

    GH-93: Frontera: Plugin-less style updates snippet

commit b531503
Merge: 2b66f11 302fe3b
Author: Wesley Bomar <[email protected]>
Date:   Tue Jul 20 16:58:15 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 2b66f11
Merge: 2bdf7e7 d0a5151
Author: Wesley Bomar <[email protected]>
Date:   Mon Jul 12 21:38:53 2021 -0500

    Merge branch 'main' into task/GH-93-GH-142-GH-133-article-list-plugins-and-styles--no-reverts

commit 2bdf7e7
Author: Wesley Bomar <[email protected]>
Date:   Mon Jul 12 20:55:42 2021 -0500

    GH-93, GH-142, GH-133: Article List Plugins+Styles
  • Loading branch information
wesleyboar committed Nov 12, 2021
1 parent 82ffc16 commit f6cb452
Show file tree
Hide file tree
Showing 30 changed files with 1,951 additions and 536 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# How to Conditionally Render Child Plugins

```handlebars
{% for plugin_instance in instance.child_plugin_instances %}
{% if plugin_instance.plugin_type == 'LinkPlugin' %}
<a href="{{ link }}" <!-- ... -->>
<!-- ... -->
</a>
{% endif %}
{% endfor %}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# How to Handle "Non-Nullable" "Default Value"

## Sample Error

```text
You are trying to add a non-nullable field '...'
to choice without a default; we can't do that
(the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option:
```

## Explanations

- (blog post) [What do you do when 'makemigrations' is telling you About your Lack of Default Value](https://chrisbartos.com/articles/what-do-you-do-when-makemigrations-is-telling-you-about-your-lack-of-default-value/)
- (video) [You are trying to add a non-nullable field ' ' to ' ' without a default; we can't do that](https://www.youtube.com/watch?v=NgaTUEijQSQ)

## Solutions

### For `cmsplugin_ptr`

1. ☑ Select option 1), then see:
- [Follow-Up Error](#follow-up-error)
- [Notes ▸ `cmsplugin_ptr`](#cmsplugin_ptr)

### For Other Fields

1. ⚠ Select option 1) and hope for the best.
2. ☑ Select option 2) and provide a sensible default (_not_ `None` a.k.a. null).
3. ⚠ (blog post) (hack) [Add A Migration For A Non-Null Foreignkey Field In Django](https://jaketrent.com/post/add-migration-nonnull-foreignkey-field-django)

## Follow-Up Error

If you allowed Null to be set as default, then you may have this new error:

```text
django.db.utils.IntegrityError: column "..." contains null values
```

Solutions:

1. [delete _relevant_ migration files and rebuild migrations](https://stackoverflow.com/a/37244199/11817077)
2. [delete _all_ migration files and rebuild migrations](https://stackoverflow.com/a/37242930/11817077)

## Notes

### `cmsplugin_ptr`

If the field is `cmsplugin_ptr` then know that

- [it is a database relationship field managed automatically by Django](https://github.com/nephila/djangocms-blog/issues/316#issuecomment-242292787),
- you may see it in workarounds for other plugins ([source a](https://github.com/django-cms/djangocms-link/blob/3.0.0/djangocms_link/models.py#L125), [source b](https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L208)),
- you should __not__ add or overwrite it unless you know what you are doing.

_W. Bomar learned everything in the intitial version of this document after trying to overwrite `cmsplugin_ptr` while extending its model from [source a](https://github.com/django-cms/djangocms-link/blob/3.0.0/djangocms_link/models.py#L125). His solution was [delete _all_ migration files and rebuild migrations](https://stackoverflow.com/a/37242930/11817077)._

## Appendix

- [Django CMS ▸ How to create Plugins ▸ Handling Relations](https://docs.django-cms.org/en/release-3.7.x/how_to/custom_plugins.html#handling-relations)
- [[BUG] Plugins with models that don't directly inherit from CMSPlugin or an abstract model cannot be copied](https://github.com/django-cms/django-cms/issues/6987)
66 changes: 66 additions & 0 deletions taccsite_cms/contrib/_docs/taccsite_static_article.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Static Article Plugins

## Intention

Support static addition of news articles that originate from a Core news site.

A [dynamic solution that pulls form the Core news site](https://github.com/TACC/Core-CMS/issues/69) is preferable.

But this is not available due to constrainst of architecture, time, or ability.

## Architecture

### (Currently) Add Image via Child Plugin Instead of Via Fields

Instead, the image fields should be in the plugin, __not__ via a child plugin, but a solution has not yet been implemented.

#### Hope for the Future

The `AbstractLink` model was successfully extended.

See:
- [./how-to-extend-django-cms-plugin.md](./how-to-extend-django-cms-plugin.md)
- [../taccsite_static_article_preview](../taccsite_static_article_preview)
- [../taccsite_static_article_list](../taccsite_static_article_list)

#### Failed Attempt

1. Build model so it extends `AbstractPicture` from `djangocms-picture`.
2. Tweak model to sweep bugs under the rug.
3. Quit when he was unable to resolve the error,
`TaccsiteStaticNewsArticlePreview has no field named 'cmsplugin_ptr_id'`
upon saving a plugin instance.
4. Learn:
- [one should not try to reduce `AbstractPicture`](https://stackoverflow.com/a/3674714/11817077)
- [one should not subclass a subclass of `CMSPlugin`](https://github.com/django-cms/django-cms/blob/3.7.4/cms/models/pluginmodel.py#L104)

#### Abandoned Code

```python
from djangocms_picture.models import AbstractPicture

# To allow user to not set image
# FAQ: Emptying the clean() method avoids picture validation
# SEE: https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L278
def skip_image_validation():
pass

class TaccsiteStaticNewsArticlePreview(AbstractPicture):
#
#
#

# Remove error-prone attribute from parent class
# FAQ: Avoid error when running `makemigrations`:
# "You are trying to add a non-nullable field 'cmsplugin_ptr' […]"
# SEE: https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L212
# SEE: https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L234
cmsplugin_ptr = None

class Meta:
abstract = False

# Validate
def clean(self):
skip_image_validation()
```
165 changes: 162 additions & 3 deletions taccsite_cms/contrib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,23 @@ def get_choices(choice_dict):



# GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe)
# Filter Django `models.CharField` `choices`
# SEE: get_choices
def filter_choices_by_prefix(choices, prefix):
"""Reduce sequence of choices to items whose values begin with given string
:param List[Tuple[str, str], ...] choices: the sequence to filter
:param str prefix: the starting text required of an item value to retain it
:returns: a sequence for django.db.models.CharField.choices
:rtype: List[Tuple[str, str], ...]
"""
new_choices = []

for choice in choices:
should_keep = choice[0].startswith(prefix)
if should_keep:
new_choices.append(choice)

return new_choices



Expand All @@ -28,7 +44,26 @@ def concat_classnames(classes):



# GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe)
# Create a list clone that has another list shoved into it
# SEE: https://newbedev.com/how-to-insert-multiple-elements-into-a-list
def insert_at_position(position, list, list_to_insert):
"""Insert list at position within another list
:returns: New list
"""
return list[:position] + list_to_insert + list[position:]



# Get the date from a list that is nearest
# SEE: https://stackoverflow.com/a/32237949/11817077
def get_nearest(items, pivot):
"""Get nearest date (or other arithmatic value)
:returns: The item value nearest the given "pivot" value
"""
return min(items, key=lambda x: abs(x - pivot))



# Get list of indicies of items that start with text
# SEE: https://stackoverflow.com/a/67393343/11817077
def get_indices_that_start_with(text, list):
Expand All @@ -39,6 +74,129 @@ def get_indices_that_start_with(text, list):
return [i for i in range(len(list)) if list[i].startswith(text)]



# Populate class attribute of plugin instances
def add_classname_to_instances(classname, plugin_instances):
"""Add class names to class attribute of plugin instances"""
for instance in plugin_instances:
# A plugin must not have any class set
if not hasattr(instance.attributes, 'class'):
instance.attributes['class'] = ''

# The class should occur before any CMS or user classes
# FAQ: This keeps plugin author classes together
instance.attributes['class'] = instance.attributes['class'] + classname



# Get date nearest today

from datetime import date

# HELP: Can this logic be less verbose?
# HELP: Is the `preferred_time_period` parameter effectual?
def which_date_is_nearest_today(date_a, date_b, preferred_time_period):
"""
Returns whether each date is today or nearest today, and whether nearest date is past or today or future.
Only two dates are supported. You may prefer 'future' or 'past' date(s).
If both dates are the same date, then both are reported as True.
:param datetime date_a: a date "A" to compare
:param datetime date_b: a date "B" to compare
:param str preferred_time_period: whether to prefer 'future' or 'past' dates
:returns:
A tuple of tuples:
((
``boolean`` of whether ``date_a`` is nearest,
``string`` of ``date_a`` time period ``past``/``today``/``future``
),
(
``boolean`` of whether ``date_b`` is nearest,
``string`` of ``date_b`` time period ``past``/``today``/``future``
)),
:rtype: tuple
"""
today = date.today()
is_a = False
is_b = False
a_time_period = 'today'
b_time_period = 'today'

# Match preferred time

if today in {date_a, date_b}:
is_a = True
is_b = True
a_time_period = 'today'
b_time_period = 'today'

elif preferred_time_period == 'future':
is_a = date_a and date_a >= today
is_b = date_b and date_b >= today
if is_a: a_time_period = 'future'
if is_b: b_time_period = 'future'
if not is_a and not is_b:
is_a = date_a and date_a < today
is_b = date_b and date_b < today
if is_a: a_time_period = 'past'
if is_b: b_time_period = 'past'

elif preferred_time_period == 'past':
is_a = date_a and date_a < today
is_b = date_b and date_b < today
if is_a: a_time_period = 'past'
if is_b: b_time_period = 'past'
if not is_a and not is_b:
is_a = date_a and date_a >= today
is_b = date_b and date_b >= today
if is_a: a_time_period = 'future'
if is_b: b_time_period = 'future'

# Show nearest date
if is_a and is_b and date_a != date_b:
nearest_date = get_nearest((date_a, date_b), today)

if date_a == nearest_date:
is_b = False
if date_b == nearest_date:
is_a = False

return ((is_a, a_time_period), (is_b, b_time_period))



# Allow plugins to set max number of nested children

from django.shortcuts import render

# SEE: https://github.com/django-cms/django-cms/issues/5102#issuecomment-597150141
class AbstractMaxChildrenPlugin():
"""
Abstract extension of `CMSPluginBase` that allows setting maximum amount of nested/child plugins.
Usage:
1. Extend this class,
after extending `CMSPluginBase` or a class that extends `CMSPluginBase`.
2. Set `max_children` to desired limit.
"""

max_children = None

def add_view(self,request, form_url='', extra_context=None):

if self.max_children:
# FAQ: Placeholders do not have a parent, only plugins do
if self._cms_initial_attributes['parent']:
num_allowed = len([v for v in self._cms_initial_attributes['parent'].get_children() if v.get_plugin_instance()[0] is not None])
else:
num_allowed = len([v for v in self.placeholder.get_plugins() if v.get_plugin_instance()[0] is not None and v.get_plugin_name() == self.name])

if num_allowed >= self.max_children:
return render(request , "path/to/your/max_reached_template.html", {
'max_children': self.max_children,
})
return super(AbstractMaxChildrenPlugin, self).add_view(request, form_url, extra_context)



# Tweak validation on Django CMS `AbstractLink` for TACC

from cms.models.pluginmodel import CMSPlugin
Expand Down Expand Up @@ -82,8 +240,9 @@ def clean(self):
if len(err.messages):
raise err

# Get name of field from a given model


# Get name of field from a given model
# SEE: https://stackoverflow.com/a/14498938/11817077
def get_model_field_name(model, field_name):
model_field_name = model._meta.get_field(field_name).verbose_name.title()
Expand Down
3 changes: 3 additions & 0 deletions taccsite_cms/contrib/taccsite_static_article_list/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Static Article List

See [./_docs/taccsite_static_article.md](./_docs/taccsite_static_article.md).
Empty file.
Loading

0 comments on commit f6cb452

Please sign in to comment.