Skip to content

Commit

Permalink
Adding news app
Browse files Browse the repository at this point in the history
  • Loading branch information
theunraveler committed Feb 1, 2018
1 parent c30fa10 commit 79b540f
Show file tree
Hide file tree
Showing 18 changed files with 470 additions and 15 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,30 @@ Read on for instructions on setting up each of apps.

4. Once you have the django admin going, go to **Sites** and add the site's domain in place of **example.com** so that the **View on Site** buttons in the admin will work correctly.

### News/Blog

1. Add app to `INSTALLED_APPS`:

```python
INSTALLED_APPS = [
...
'eti_marketing',
'eti_marketing.news',
'ckeditor',
]
```

2. Include the URLs in your main URL conf. Usually, we like to put these URLs
into some kind of namespace.

```python
url(r'^news/', include('eti_marketing.news.urls')),
```

3. Run `python manage.py migrate` to run the database migrations.

4. Once you have the django admin going, go to **Sites** and add the site's domain in place of **example.com** so that the **View on Site** buttons in the admin will work correctly.

### Signup Form

A signup form that talks with Active Campaign is included. To use it, set the
Expand Down
17 changes: 2 additions & 15 deletions eti_marketing/landing_page/views.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
from django.views.generic import DetailView as BaseDetailView

from .models import LandingPage
from eti_marketing.utils import get_base_template
from eti_marketing.utils import BaseTemplateMixin, PublishedQuerysetMixin


class DetailView(BaseDetailView):
class DetailView(PublishedQuerysetMixin, BaseTemplateMixin, BaseDetailView):
model = LandingPage
template_name = 'eti_marketing/landing_page/detail.html'
context_object_name = 'landing'

def get_queryset(self):
queryset = super().get_queryset()

if not self.request.user.is_superuser:
queryset = queryset.published()

return queryset

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['base_template'] = get_base_template()
return context
1 change: 1 addition & 0 deletions eti_marketing/news/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default_app_config = 'eti_marketing.news.apps.NewsConfig'
55 changes: 55 additions & 0 deletions eti_marketing/news/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from django.contrib import admin
from django.utils.translation import ugettext as _, ugettext_lazy as __

from .models import Article


def make_published(modeladmin, request, queryset):
queryset.update(page_status=True)


make_published.short_description = __('Publish Selected Pages')


def make_unpublished(modeladmin, request, queryset):
queryset.update(page_status=False)


make_unpublished.short_description = __('Hide Selected Pages')


@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
readonly_fields = ['last_updated']
prepopulated_fields = {"slug": ["title"]}
list_display = ['short_title', 'added_date', 'last_updated', 'published']
list_filter = ['title', 'added_date', 'last_updated', 'published']
search_fields = ['title']
actions = [make_published, make_unpublished]
view_on_site = True
save_as = True

fieldsets = (
(None, {
'fields': ('title', 'slug', 'last_updated',)
}),
(__('Header'), {
'fields': (('header', 'header_bg'), 'subheader',)
}),
(__('Layout'), {
'fields': ('columns', 'column_1', 'column_2', 'sidebar', 'sidebar_text', 'footer')
}),
(__('Calls to Action'), {
'fields': ('cta', ('cta_text', 'cta_url'), 'socials', ('addthis_pubid'))
}),
(__('Additional SEO'), {
'classes': ('collapse',),
'fields': ('seo_keywords', 'seo_description')
}),
(__('Page Status'), {'fields': ('published',)})
)

def get_changeform_initial_data(self, request):
return {
'cta_text': _('Contact Us')
}
7 changes: 7 additions & 0 deletions eti_marketing/news/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _


class NewsConfig(AppConfig):
name = 'eti_marketing.news'
verbose_name = _('News Articles')
47 changes: 47 additions & 0 deletions eti_marketing/news/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2018-02-01 10:36
from __future__ import unicode_literals

import ckeditor.fields
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='Article',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(help_text='Try not to exceed more than 50 characters (for aesthetic reasons).', max_length=200, verbose_name='Page Title')),
('slug', models.SlugField(unique=True)),
('header', models.BooleanField(default=True, help_text='Generic header with a background', verbose_name='Header with background image')),
('subheader', models.CharField(blank=True, help_text='This is the article title and should be a bit longer than the page title.', max_length=200, verbose_name='Tagline')),
('seo_keywords', models.CharField(blank=True, max_length=50, null=True, verbose_name='Meta Keywords')),
('seo_description', models.CharField(blank=True, max_length=100, null=True, verbose_name='Meta Description')),
('columns', models.CharField(choices=[('FULL', 'Full Width'), ('HALF', 'Two Columns')], default='FULL', max_length=4)),
('sidebar', models.BooleanField(default=False, verbose_name='Turn sidebar on?')),
('column_1', ckeditor.fields.RichTextField(help_text='This is left content box')),
('column_2', ckeditor.fields.RichTextField(blank=True, help_text="You don't have to fill this in if you have only one column")),
('sidebar_text', ckeditor.fields.RichTextField(blank=True, help_text='Sidebar Text if <b>Sidebar</b> is turned on')),
('cta', models.BooleanField(default=True, verbose_name='Call to Action Button?')),
('cta_text', models.CharField(blank=True, default='More News Articles', help_text='Default is: More News Articles', max_length=30, null=True, verbose_name='Button Text')),
('cta_url', models.CharField(blank=True, default='/news/', help_text='Within our site: /news/. External Site: https://google.com/', max_length=300, null=True, verbose_name='Button URL')),
('footer', models.BooleanField(default=True, verbose_name='Show Footer?')),
('socials', models.BooleanField(default=False, verbose_name='Social Icons?')),
('addthis_pubid', models.CharField(blank=True, help_text='This is the string that is AFTER `#pubid=`. Ex: ra-5a61fe428f3a39a8', max_length=25, null=True, verbose_name='AddThis PubId')),
('added_date', models.DateTimeField(auto_now_add=True, verbose_name='Date Added')),
('last_updated', models.DateTimeField(auto_now=True, verbose_name='Last Update')),
('published', models.BooleanField(default=False, help_text='Unpublished pages are only visible to admins.', verbose_name='Publish Page?')),
],
options={
'verbose_name': 'News Article',
'verbose_name_plural': 'News Articles',
},
),
]
Empty file.
69 changes: 69 additions & 0 deletions eti_marketing/news/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from django.db import models
from django.template.defaultfilters import truncatewords
from django.utils.translation import ugettext as _, ugettext_lazy as __
from django.utils.encoding import python_2_unicode_compatible
from django.core.exceptions import ValidationError
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse

from ckeditor.fields import RichTextField


class ArticleQuerySet(models.query.QuerySet):

def published(self):
return self.filter(published=True)


@python_2_unicode_compatible
class Article(models.Model):

LAYOUT_FULL = 'FULL'
LAYOUT_HALF = 'HALF'
LAYOUTS = (
(LAYOUT_FULL, __('Full Width')),
(LAYOUT_HALF, __('Two Columns')),
)

title = models.CharField(__('Page Title'), max_length=200, help_text=__('Try not to exceed more than 50 characters (for aesthetic reasons).'))
slug = models.SlugField(max_length=50, unique=True)
header = models.BooleanField(__('Header with background image'), default=True, help_text=__('Generic header with a background'))
subheader = models.CharField(__('Tagline'), max_length=200, help_text=__('This is the article title and should be a bit longer than the page title.'), blank=True)
seo_keywords = models.CharField(__('Meta Keywords'), max_length=50, blank=True, null=True)
seo_description = models.CharField(__('Meta Description'), max_length=100, blank=True, null=True)
columns = models.CharField(max_length=4, choices=LAYOUTS, default=LAYOUT_FULL)
sidebar = models.BooleanField(__('Turn sidebar on?'), default=False)
column_1 = RichTextField(help_text=__('This is left content box'))
column_2 = RichTextField(help_text=__('You don\'t have to fill this in if you have only one column'), blank=True)
sidebar_text = RichTextField(help_text=__('Sidebar Text if <b>Sidebar</b> is turned on'), blank=True)
cta = models.BooleanField(__('Call to Action Button?'), default=True)
cta_text = models.CharField(__('Button Text'), max_length=30, blank=True, null=True, default='More News Articles', help_text=__('Default is: More News Articles'))
cta_url = models.CharField(__('Button URL'), max_length=300, blank=True, null=True, default="/news/", help_text=_('Within our site: /news/. External Site: https://google.com/'))
footer = models.BooleanField(__('Show Footer?'), default=True)
socials = models.BooleanField(__('Social Icons?'), default=False)
addthis_pubid = models.CharField(__('AddThis PubId'), max_length=25, null=True, blank=True, help_text=__('This is the string that is AFTER `#pubid=`. Ex: ra-5a61fe428f3a39a8'))
added_date = models.DateTimeField(__('Date Added'), auto_now_add=True)
last_updated = models.DateTimeField(__('Last Update'), auto_now=True)
published = models.BooleanField(__('Publish Page?'), default=False, help_text=__('Unpublished pages are only visible to admins.'))

objects = ArticleQuerySet.as_manager()

@property
def short_title(self):
return truncatewords(self.title, 5)

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

def clean(self):
if self.socials and not self.addthis_pubid:
raise ValidationError(_('AddThis PubId is required'))

def __str__(self):
return self.title

class Meta:
verbose_name = __('News Article')
verbose_name_plural = __('News Articles')
74 changes: 74 additions & 0 deletions eti_marketing/news/templates/eti_marketing/news/detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{% extends base_template %}
{% load i18n %}

{% block title %}
{{ block.super }}{{ article.title }}
{% endblock title %}

{% block meta_keywords %}
{{ article.seo_keywords }}
{% endblock %}
{% block meta_description %}
{{ article.seo_description }}
{% endblock %}
{% block extra_meta %}
<meta property="og:url" content="{{ current_url }}" />
<meta property="og:type" content="article" />
<meta property="og:title" content="{{ article.title }}" />
<meta property="og:description" content="{{ article.column_1|striptags|truncatewords:25 }}" />
{% endblock extra_meta %}

{% block content %}
<article class="article">
<section class="page-content page-landing-content{% if article.sidebar %} has-sidebar{% endif %}">
{% if article.sidebar %}
<aside class="page-landing-sidebar">
{{ article.sidebar_text|safe }}
</aside>
{% endif %}

<div class="article-body {{ article.columns|lower }}">
<div class="row no-gutters">

{% if article.subheader %}
<header class="page-landing-headers">
<h2 class="page-landing-title">{{ article.subheader }}</h2>
</header>
{% endif %}

{% if article.columns == "HALF" %}
<div class="page-content-left">
{{ article.column_1|safe }}
</div>
<div class="page-content-right">
{{ article.column_2|safe }}
</div>
{% else %}
<div class="col-12 pl-0">
{{ article.column_1|safe }}
</div>
{% endif %}
</div>

<div class="col-12 pl-0 mt-4">
{% if article.cta %}
{{ cta_html|safe }}
{% endif %}

{% if article.socials %}
<div class="page-landing-socials">
<h5 class="h6 text-uppercase">{% trans "Share this article" %}</h5>
<script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid={{ article.addthis_pubid }}"></script>
<div class="social-media">
<div class="addthis_inline_share_toolbox"></div>
</div>
</div>
{% endif %}
</div>
</section>

{% if article.footer %}
{% include 'includes/page-footer.html' %}
{% endif %}
</article>
{% endblock %}
42 changes: 42 additions & 0 deletions eti_marketing/news/templates/eti_marketing/news/list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% extends base_template %}
{% load i18n %}

{% block title %}
{% trans "News" %}
{% endblock title %}

{% block content %}
<article class="page-news">
<div class="page-content">
<article class="news-articles">
{% for article in news %}
<div class="news-article">
<div class="news-article-description">
<h4 class="news-article-title">
<a href="{{ article.get_absolute_url }}">
{{ article.title|truncatewords_html:8 }}
</a>
<small class="news-article-date">{{ article.added_date|date:"m/d/y" }}</small>
</h4>

<div class="news-article-text">
{{ article.column_1|safe|truncatewords_html:20 }}
</div>
</div>

<footer class="news-article-footer">
<a href="{{ article.get_absolute_url }}" class="btn btn-primary">
{% trans "Read More" %}
</a>
</footer>
</div>
{% empty %}
<section class="col-12 text-center">
<h3 class="text-uppercase mb-4">{% trans "No articles available" %}</h3>
</section>
{% endfor %}
</article>
</div>
</article>
{% endblock %}

8 changes: 8 additions & 0 deletions eti_marketing/news/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.conf.urls import url
from . import views


urlpatterns = [
url(r'^$', views.ListView.as_view(), name='news-article-list'),
url(r'^(?P<slug>[^\.]+)/$', views.DetailView.as_view(), name='news-article-detail'),
]
17 changes: 17 additions & 0 deletions eti_marketing/news/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django.views.generic import (
ListView as BaseListView,
DetailView as BaseDetailView,
)

from .models import Article
from eti_marketing.utils import BaseTemplateMixin, PublishedQuerysetMixin


class ListView(PublishedQuerysetMixin, BaseTemplateMixin, BaseListView):
model = Article
template_name = 'eti_marketing/news/list.html'


class DetailView(PublishedQuerysetMixin, BaseTemplateMixin, BaseDetailView):
model = Article
template_name = 'eti_marketing/news/detail.html'
Loading

0 comments on commit 79b540f

Please sign in to comment.