Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Blog Content Type snippet and added it to news articles #1269

Merged
merged 14 commits into from
May 10, 2022
Merged
36 changes: 36 additions & 0 deletions news/migrations/0036_blogtype_contenttype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 3.2.9 on 2022-04-12 13:02

from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields


class Migration(migrations.Migration):

dependencies = [
('snippets', '0020_blogcontenttype'),
('news', '0035_auto_20210226_1150'),
]

operations = [
migrations.CreateModel(
name='ContentType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('blog_content_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='newsarticle_content_type', to='snippets.blogcontenttype')),
],
),
migrations.CreateModel(
name='BlogType',
fields=[
('contenttype_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='news.contenttype')),
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
('blog_category', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='blog_type', to='news.newsarticle')),
],
options={
'ordering': ['sort_order'],
'abstract': False,
},
bases=('news.contenttype', models.Model),
),
]
21 changes: 21 additions & 0 deletions news/migrations/0037_newsarticle_collections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.9 on 2022-04-20 18:22

from django.db import migrations
import wagtail.core.blocks
import wagtail.core.fields
import wagtail.snippets.blocks


class Migration(migrations.Migration):

dependencies = [
('news', '0036_blogtype_contenttype'),
]

operations = [
migrations.AddField(
model_name='newsarticle',
name='collections',
field=wagtail.core.fields.StreamField([('collection', wagtail.core.blocks.ListBlock(wagtail.core.blocks.StructBlock([('collection', wagtail.snippets.blocks.SnippetChooserBlock(label='Blog Collection', required=True, target_model='BlogCollection')), ('featured', wagtail.core.blocks.BooleanBlock(label='Featured')), ('popular', wagtail.core.blocks.BooleanBlock(label='Popular'))])))], null=True),
),
]
26 changes: 26 additions & 0 deletions news/migrations/0038_auto_20220420_1547.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 3.2.9 on 2022-04-20 20:47

from django.db import migrations
import news.models
import wagtail.core.blocks
import wagtail.core.fields


class Migration(migrations.Migration):

dependencies = [
('news', '0037_newsarticle_collections'),
]

operations = [
migrations.AddField(
model_name='newsarticle',
name='article_subjects',
field=wagtail.core.fields.StreamField([('subject', wagtail.core.blocks.ListBlock(wagtail.core.blocks.StructBlock([('subject', news.models.BlogCollectionChooserBlock(label='Blog Subject', required=True, target_model='snippets.Subject'))])))], null=True),
),
migrations.AlterField(
model_name='newsarticle',
name='collections',
field=wagtail.core.fields.StreamField([('collection', wagtail.core.blocks.ListBlock(wagtail.core.blocks.StructBlock([('collection', news.models.BlogCollectionChooserBlock(label='Blog Collection', required=True, target_model='snippets.BlogCollection')), ('featured', wagtail.core.blocks.BooleanBlock(label='Featured', required=False)), ('popular', wagtail.core.blocks.BooleanBlock(label='Popular', required=False))])))], null=True),
),
]
31 changes: 31 additions & 0 deletions news/migrations/0039_auto_20220427_1107.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 3.2.9 on 2022-04-27 16:07

from django.db import migrations
import news.models
import wagtail.core.blocks
import wagtail.core.fields


class Migration(migrations.Migration):

dependencies = [
('news', '0038_auto_20220420_1547'),
]

operations = [
migrations.RemoveField(
model_name='contenttype',
name='blog_content_type',
),
migrations.AddField(
model_name='newsarticle',
name='content_types',
field=wagtail.core.fields.StreamField([('content_type', wagtail.core.blocks.ListBlock(wagtail.core.blocks.StructBlock([('conte_type', news.models.ContentTypeChooserBlock(label='Blog Content Type', required=True, target_model='snippets.BlogContentType'))])))], null=True),
),
migrations.DeleteModel(
name='BlogType',
),
migrations.DeleteModel(
name='ContentType',
),
]
21 changes: 21 additions & 0 deletions news/migrations/0040_alter_newsarticle_content_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.9 on 2022-04-27 16:21

from django.db import migrations
import news.models
import wagtail.core.blocks
import wagtail.core.fields


class Migration(migrations.Migration):

dependencies = [
('news', '0039_auto_20220427_1107'),
]

operations = [
migrations.AlterField(
model_name='newsarticle',
name='content_types',
field=wagtail.core.fields.StreamField([('content_type', wagtail.core.blocks.ListBlock(wagtail.core.blocks.StructBlock([('content_type', news.models.ContentTypeChooserBlock(label='Blog Content Type', required=True, target_model='snippets.BlogContentType'))])))], null=True),
),
]
132 changes: 130 additions & 2 deletions news/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from wagtail.embeds.blocks import EmbedBlock
from wagtail.search import index
from wagtail.core import blocks
from wagtail.core.blocks import TextBlock, StructBlock, StreamBlock, FieldBlock, CharBlock, RichTextBlock, RawHTMLBlock
from wagtail.core.blocks import TextBlock, StructBlock, StreamBlock, FieldBlock, CharBlock, RichTextBlock, RawHTMLBlock, BooleanBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.snippets.blocks import SnippetChooserBlock
Expand All @@ -25,7 +25,8 @@
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase
from openstax.functions import build_image_url
from snippets.models import NewsSource
from snippets.models import NewsSource, BlogContentType, BlogCollection, Subject


class ImageChooserBlock(ImageChooserBlock):
def get_api_representation(self, value, context=None):
Expand Down Expand Up @@ -66,6 +67,44 @@ class BlogStreamBlock(StreamBlock):
embed = EmbedBlock(icon="media", label="Embed Media URL")


class BlogCollectionChooserBlock(SnippetChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'name': value.name,
}


class SubjectChooserBlock(SnippetChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'name': value.name,
}


class ContentTypeChooserBlock(SnippetChooserBlock):
def get_api_representation(self, value, context=None):
if value:
return {
'content_type': value.content_type,
}


class SubjectBlock(StructBlock):
subject = BlogCollectionChooserBlock(required=True, label='Blog Subject', target_model='snippets.Subject')


class BlogCollectionBlock(StructBlock):
collection = BlogCollectionChooserBlock(required=True, label='Blog Collection', target_model='snippets.BlogCollection')
featured = BooleanBlock(label="Featured", required=False)
popular = BooleanBlock(label="Popular", required=False)


class BlogContentTypeBlock(StructBlock):
content_type = ContentTypeChooserBlock(required=True, label='Blog Content Type', target_model='snippets.BlogContentType')


class NewsIndex(Page):
intro = RichTextField(blank=True)
press_kit = models.ForeignKey(
Expand Down Expand Up @@ -122,6 +161,50 @@ class NewsArticleTag(TaggedItemBase):
content_object = ParentalKey('news.NewsArticle', related_name='tagged_items')


def news_article_search(collection, content_types=None, subjects=None):
if subjects is None:
subjects = []
if content_types is None:
content_types = []
news_articles = NewsArticle.objects.all()
collection_articles = []
articles_to_return = []

for na in news_articles:
if collection is not None and collection in na.blog_collections:
collection_articles.append(na)

if len(collection_articles) > 0:
if len(content_types) > 0 and len(subjects) > 0:
for article in collection_articles:
blog_types = article.blog_content_types
blog_subjects = article.blog_subjects
added = False
for item in content_types:
if item in blog_types:
articles_to_return.append(article)
added = True
for item in subjects:
if item in blog_subjects and not added:
articles_to_return.append(article)
elif len(content_types) > 0 and len(subjects) == 0:
for article in collection_articles:
blog_types = article.blog_content_types
for item in content_types:
if item in blog_types:
articles_to_return.append(article)
elif len(content_types) == 0 and len(subjects) > 0:
for article in collection_articles:
blog_subjects = article.blog_subjects
for item in subjects:
if item in blog_subjects:
articles_to_return.append(article)
else:
articles_to_return = collection_articles

return articles_to_return


class NewsArticle(Page):
date = models.DateField("Post date")
heading = models.CharField(max_length=250, help_text="Heading displayed on website")
Expand All @@ -142,6 +225,15 @@ def get_article_image(self):
tags = ClusterTaggableManager(through=NewsArticleTag, blank=True)
body = StreamField(BlogStreamBlock())
pin_to_top = models.BooleanField(default=False)
collections = StreamField(blocks.StreamBlock([
('collection', blocks.ListBlock(BlogCollectionBlock())
)]), null=True)
article_subjects = StreamField(blocks.StreamBlock([
('subject', blocks.ListBlock(SubjectBlock())
)]), null=True)
content_types = StreamField(blocks.StreamBlock([
('content_type', blocks.ListBlock(BlogContentTypeBlock())
)]), null=True)
promote_image = models.ForeignKey(
'wagtailimages.Image',
null=True,
Expand All @@ -164,6 +256,36 @@ def body_blurb(self):

return str(first_paragraph_parsed[0])

@property
def blog_content_types(self):
prep_value = self.content_types.get_prep_value()
types = []
for t in prep_value:
type_id = t['value'][0]['content_type']
type = BlogContentType.objects.filter(id=type_id)
types.append(str(type[0]))
return types

@property
def blog_subjects(self):
prep_value = self.article_subjects.get_prep_value()
subjects = []
for s in prep_value:
subject_id = s['value'][0]['subject']
subject = Subject.objects.filter(id=subject_id)
subjects.append(str(subject[0]))
return subjects

@property
def blog_collections(self):
prep_value = self.collections.get_prep_value()
cols = []
for c in prep_value:
collection_id = c['value'][0]['collection']
collection = BlogCollection.objects.filter(id=collection_id)
cols.append(str(collection[0]))
return cols

search_fields = Page.search_fields + [
index.SearchField('body'),
index.SearchField('tags'),
Expand All @@ -180,6 +302,9 @@ def body_blurb(self):
FieldPanel('tags'),
StreamFieldPanel('body'),
FieldPanel('pin_to_top'),
StreamFieldPanel('collections'),
StreamFieldPanel('article_subjects'),
StreamFieldPanel('content_types'),
]

promote_panels = [
Expand All @@ -205,6 +330,9 @@ def body_blurb(self):
APIField('slug'),
APIField('seo_title'),
APIField('search_description'),
APIField('collections'),
APIField('article_subjects'),
APIField('content_types'),
APIField('promote_image')
]

Expand Down
22 changes: 19 additions & 3 deletions news/search.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@

import re

from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
from django.http import JsonResponse

from news.models import NewsArticle
from news.models import NewsArticle, news_article_search


def normalize_query(query_string, findterms=re.compile(r'"([^"]+)"|(\S+)').findall, normspace=re.compile(r'\s{2,}').sub):
"""
Expand Down Expand Up @@ -63,6 +65,18 @@ def search(request):
search=vector,
).filter(search=query).order_by('rank', '-date')

if ('collection' in request.GET) and request.GET['collection'].strip():
collection_name = request.GET['collection']
types = []
subjects = []
if ('types' in request.GET) and request.GET['types'].strip():
types = request.GET['types'].split(',')

if ('subjects' in request.GET) and request.GET['subjects'].strip():
subjects = request.GET['subjects'].split(',')

found_entries = news_article_search(collection_name, types, subjects)

search_results_json = []
search_results_shown = set()
for result in found_entries:
Expand All @@ -82,10 +96,12 @@ def search(request):
'author': result.author,
'pin_to_top': result.pin_to_top,
'tags': list(result.tags.names()),
'collections': result.blog_collections,
'article_subjects': result.blog_subjects,
'content_types': result.blog_content_types,
'slug': result.slug,
'seo_title': result.seo_title,
'search_description': result.search_description,
})

return JsonResponse(search_results_json, safe=False)
return JsonResponse([], safe=False)

Loading