From 4ca7c86ec5090854032e9b7de42f51035bacf212 Mon Sep 17 00:00:00 2001 From: Evert Date: Thu, 5 Oct 2017 13:37:09 +0300 Subject: [PATCH] initial layout --- .gitignore | 5 + EpisodesCommunity/settings.py | 32 ++- EpisodesCommunity/urls.py | 4 +- LandingPage/migrations/0001_initial.py | 317 ++++++++++++++++++++++++ LandingPage/static/css/footer.styl | 76 ++++++ LandingPage/static/css/style.styl | 58 +++++ LandingPage/templates/base.html | 37 +++ LandingPage/templates/landing_page.html | 46 +++- LandingPage/views.py | 9 +- requirements.txt | 3 +- 10 files changed, 573 insertions(+), 14 deletions(-) create mode 100644 .gitignore create mode 100644 LandingPage/migrations/0001_initial.py create mode 100644 LandingPage/static/css/footer.styl create mode 100644 LandingPage/static/css/style.styl create mode 100644 LandingPage/templates/base.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79b066f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/static/ +/media/ +/options.ini +/database.* +*.py[cod] diff --git a/EpisodesCommunity/settings.py b/EpisodesCommunity/settings.py index 56f9aa1..f4926d8 100644 --- a/EpisodesCommunity/settings.py +++ b/EpisodesCommunity/settings.py @@ -46,6 +46,7 @@ INSTALLED_APPS = [ 'LandingPage.apps.LandingpageConfig', 'Show.apps.ShowConfig', 'Discussions.apps.DiscussionsConfig', + 'pipeline', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -129,10 +130,39 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ +MEDIA_URL = '/media/' +MEDIA_ROOT = 'media/' + STATIC_URL = '/static/' +STATIC_ROOT = 'static/' +PIPELINE = { + 'PIPELINE_ENABLED': not DEBUG, + 'STYLESHEETS': { + 'style': { + 'source_filenames': ( + 'css/style.styl', + 'css/footer.styl', + ), + 'output_filename': 'css/style.css', + }, + }, + 'COMPILERS': [ + 'pipeline.compilers.stylus.StylusCompiler' + ], + 'CSS_COMPRESSOR': 'pipeline.compressors.NoopCompressor', + 'JS_COMPRESSOR': 'pipeline.compressors.NoopCompressor', +} -AUTH_TOKEN_ENDPOINT = oauth_options.get('token_endpoint','https://icynet.eu/oauth/') +STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage' + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'pipeline.finders.PipelineFinder', +) + +AUTH_TOKEN_ENDPOINT = oauth_options.get('token_endpoint','https://icynet.eu/oauth2/') AUTH_CLIENT_ID = oauth_options.get('client_id') AUTH_B64 = base64.b64encode(bytearray('%s:%s'%(AUTH_CLIENT_ID,oauth_options.get('client_secret')),'utf-8')).decode("utf-8") AUTH_REDIRECT_URL = oauth_options.get('redirect_url') diff --git a/EpisodesCommunity/urls.py b/EpisodesCommunity/urls.py index b24ce88..e7a72a8 100644 --- a/EpisodesCommunity/urls.py +++ b/EpisodesCommunity/urls.py @@ -13,10 +13,12 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ +from django.conf import settings from django.conf.urls import url, include from django.contrib import admin +from django.conf.urls.static import static urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('LandingPage.urls')) -] +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/LandingPage/migrations/0001_initial.py b/LandingPage/migrations/0001_initial.py new file mode 100644 index 0000000..95a7d2b --- /dev/null +++ b/LandingPage/migrations/0001_initial.py @@ -0,0 +1,317 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-10-04 19:15 +from __future__ import unicode_literals + +import LandingPage.models +import django.core.files.storage +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Ban', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('reason', models.CharField(blank=True, help_text='The reason this user was banned', max_length=50, verbose_name='Ban Reason')), + ('expiration', models.DateField(blank=True, help_text='The date this user will become unbanned', verbose_name='Expiration Date')), + ('permanent', models.BooleanField(help_text='If checked, this user will never be unbanned, even if the expiration date passes', verbose_name='Permanent')), + ('site_wide', models.BooleanField(help_text='If checked, this is a site-wide ban, and the user is automatically banned from all shows, not just those in the Banned From (scope) paramenter', verbose_name='Site Wide Ban')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='DiscussionBoard', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('title', models.CharField(help_text='The title of the discussion', max_length=100)), + ('body', models.TextField(help_text='The body of the post', verbose_name='Body')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='DiscussionReply', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('body', models.TextField(help_text='The body of the response', verbose_name='Body')), + ('board', models.ForeignKey(help_text='The discussion board this was created in reply to', on_delete=django.db.models.deletion.CASCADE, related_name='replies', to='LandingPage.DiscussionBoard')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='DiscussionVote', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('postive', models.BooleanField(help_text='If true, the vote is an upvote. Otherwise, it is a downvote. Neutral votes are not recorded')), + ('board', models.ForeignKey(help_text='The board this vote was cast on', on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='LandingPage.DiscussionBoard')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Episode', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('episode', models.IntegerField(help_text='The position of this episode in the season. The first episode of the season to air would be episode number 1', verbose_name='Episode Number')), + ('name', models.CharField(help_text='The name given to this episode by its producers', max_length=40, verbose_name='Episode Season')), + ('summary', models.TextField(help_text='A summary of this episode')), + ('airdate', models.DateField(help_text='The date this episode officially aired for the first time', verbose_name='Original Air Date')), + ], + ), + migrations.CreateModel( + name='Favorite', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('episode', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='LandingPage.Episode')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Report', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('title', models.CharField(help_text='A brief summary of the report', max_length=50, verbose_name='Title')), + ('details', models.TextField(help_text='The details of the report, preferably including why the content should be removed', verbose_name='Details')), + ('url', models.URLField(help_text='The URL of the content being reported', max_length=100, verbose_name='Content URL')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Season', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, help_text='The name given to this season by its producers. Can be blank if no name was given', max_length=40, verbose_name='Season Name')), + ('number', models.IntegerField(help_text='The number of this season, starting at 1; For example, the first season to be aired would be number 1, and the second would be number 2')), + ('description', models.TextField(help_text="A description of this season's happenings")), + ('artwork', models.ImageField(blank=True, help_text='The artwork associated with the season. Should display the name of the show in a movie-poster esque format. Aspect ration should be about 2:3', storage=django.core.files.storage.FileSystemStorage(base_url='showstatic', location='uploaded_resources'), upload_to=LandingPage.models.name_season_artwork, verbose_name='Artwork')), + ], + ), + migrations.CreateModel( + name='Show', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('name', models.CharField(help_text='The full name of the show', max_length=40, verbose_name='Full Name')), + ('abbr', models.SlugField(help_text='A short abbreviation of the show, for use in urls', max_length=5, unique=True, verbose_name='Abbreviation')), + ('description', models.TextField(help_text='A description of the show', verbose_name='Description')), + ('release', models.DateField(help_text='The release date of the first episode of the show', verbose_name='Release Date')), + ('artwork', models.ImageField(help_text='The artwork associated with the show. Should display the name of the show in a movie-poster esque format. Aspect ration should be about 2:3', storage=django.core.files.storage.FileSystemStorage(base_url='showstatic', location='uploaded_resources'), upload_to=LandingPage.models.name_artwork, verbose_name='Artwork')), + ('imdb', models.URLField(help_text='The url of the IMDb page for this show', verbose_name='IMDb Page')), + ('moderated', models.BooleanField(help_text='Whether or not this show is user-moderated', verbose_name='User Moderated')), + ('css', models.FileField(help_text="The CSS stylesheet applied to this show's page", storage=django.core.files.storage.FileSystemStorage(base_url='showstatic', location='uploaded_resources'), upload_to=LandingPage.models.name_css, verbose_name='Custom Style')), + ('banner', models.ImageField(help_text="A banner used for the show's page.", storage=django.core.files.storage.FileSystemStorage(base_url='showstatic', location='uploaded_resources'), upload_to=LandingPage.models.name_banner, verbose_name='Artwork')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ShowModerator', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ShowSubmission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('details', models.TextField(help_text='Some details about the show. Why it should be added, where information about it can be found, etc.', verbose_name='Details')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Submission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('url', models.URLField(help_text='The link that was submitted')), + ('tags', models.CharField(help_text='Tags applied to this link submission', max_length=200)), + ('episode', models.ForeignKey(help_text='What episode this link contains a mirror of', on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to='LandingPage.Episode', verbose_name='Submitted For')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='SubmissionVote', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('positive', models.BooleanField(help_text='If this is true, the vote is an upvote. Otherwise, it is a downvote')), + ('submission', models.ForeignKey(help_text='What this submission was cast on', on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='LandingPage.Submission')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('user_id', models.CharField(help_text="The UUID assigned to this user by IcyNet's auth servers", max_length=36)), + ('email', models.EmailField(help_text="This user's email address", max_length=254)), + ('display_name', models.CharField(help_text='The name shown to other users', max_length=20, verbose_name='Display Name')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Watch', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True, help_text='The date and time this object was created')), + ('episode', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='LandingPage.Episode')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Admin', + fields=[ + ('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='LandingPage.User')), + ], + options={ + 'abstract': False, + }, + bases=('LandingPage.user',), + ), + migrations.AddField( + model_name='watch', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='LandingPage.User'), + ), + migrations.AddField( + model_name='user', + name='favorites', + field=models.ManyToManyField(related_name='favorited_by', through='LandingPage.Favorite', to='LandingPage.Episode'), + ), + migrations.AddField( + model_name='user', + name='watches', + field=models.ManyToManyField(related_name='watched_by', through='LandingPage.Watch', to='LandingPage.Episode'), + ), + migrations.AddField( + model_name='submissionvote', + name='user', + field=models.ForeignKey(help_text='The user who cast this vote', on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='LandingPage.User'), + ), + migrations.AddField( + model_name='submission', + name='user', + field=models.ForeignKey(help_text='The user who submitted this link', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='submissions', to='LandingPage.User'), + ), + migrations.AddField( + model_name='showsubmission', + name='user', + field=models.ForeignKey(help_text='The user who submitted this show', on_delete=django.db.models.deletion.CASCADE, related_name='show_submissions', to='LandingPage.User', verbose_name='Submitter'), + ), + migrations.AddField( + model_name='showmoderator', + name='appointed_by', + field=models.ForeignKey(help_text='The user who appointed this moderator', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='appointed_mods', to='LandingPage.User', verbose_name='Appointed by'), + ), + migrations.AddField( + model_name='showmoderator', + name='show', + field=models.ForeignKey(help_text='The show this user moderates', on_delete=django.db.models.deletion.CASCADE, related_name='moderators', to='LandingPage.Show', verbose_name='Moderated Show'), + ), + migrations.AddField( + model_name='showmoderator', + name='user', + field=models.ForeignKey(help_text='The user who moderates this show', on_delete=django.db.models.deletion.CASCADE, related_name='moderated_shows', to='LandingPage.User', verbose_name='Moderator'), + ), + migrations.AddField( + model_name='season', + name='show', + field=models.ForeignKey(help_text='The show this season belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='seasons', to='LandingPage.Show'), + ), + migrations.AddField( + model_name='report', + name='reporter', + field=models.ForeignKey(help_text='The user who created this report', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='reports', to='LandingPage.User', verbose_name='Reporter'), + ), + migrations.AddField( + model_name='favorite', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='LandingPage.User'), + ), + migrations.AddField( + model_name='episode', + name='season', + field=models.ForeignKey(help_text='The season this episode is from', on_delete=django.db.models.deletion.CASCADE, related_name='episodes', to='LandingPage.Season'), + ), + migrations.AddField( + model_name='episode', + name='show', + field=models.ForeignKey(help_text='The show this episode belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='episodes', to='LandingPage.Show'), + ), + migrations.AddField( + model_name='discussionvote', + name='user', + field=models.ForeignKey(help_text='The user which cast this vote', on_delete=django.db.models.deletion.CASCADE, related_name='discussion_votes', to='LandingPage.User'), + ), + migrations.AddField( + model_name='discussionreply', + name='user', + field=models.ForeignKey(help_text='The user that posted this reply', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replies', to='LandingPage.User'), + ), + migrations.AddField( + model_name='discussionboard', + name='show', + field=models.ForeignKey(help_text='The show this discussion was created for', on_delete=django.db.models.deletion.CASCADE, related_name='discussion_boards', to='LandingPage.Show'), + ), + migrations.AddField( + model_name='discussionboard', + name='user', + field=models.ForeignKey(help_text='The user that created this discussion', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='discussion_boards', to='LandingPage.User'), + ), + migrations.AddField( + model_name='ban', + name='scope', + field=models.ManyToManyField(help_text='The shows this user is banned from interacting with', related_name='bans', to='LandingPage.Show', verbose_name='Banned From'), + ), + migrations.AddField( + model_name='ban', + name='user', + field=models.OneToOneField(help_text='The user this ban applies to', on_delete=django.db.models.deletion.CASCADE, to='LandingPage.User', verbose_name='Banned User'), + ), + migrations.AddField( + model_name='ban', + name='admin', + field=models.ForeignKey(help_text='The admin which banned this user', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bans', to='LandingPage.Admin', verbose_name='Banned By'), + ), + ] diff --git a/LandingPage/static/css/footer.styl b/LandingPage/static/css/footer.styl new file mode 100644 index 0000000..8898fc5 --- /dev/null +++ b/LandingPage/static/css/footer.styl @@ -0,0 +1,76 @@ +footer + padding: 20px + background: #e9f6fd + background: -moz-linear-gradient(top, #e9f6fd 0%, #d3eefb 100%) + background: -webkit-linear-gradient(top, #e9f6fd 0%,#d3eefb 100%) + background: linear-gradient(to bottom, #e9f6fd 0%,#d3eefb 100%) + border-top: 1px solid #ddd + text-align: center + .copyright + display: inline-block + text-align: center + font-size: 90% + vertical-align: top + margin-top: 35px + padding: 15px + margin-left: 5vw + .squeebot + width: 200px + .logo + font-family: "Open Sans" + font-weight: bold + text-transform: uppercase + text-shadow: 2px 2px 1px #007104 + color: #00b300 + letter-spacing: 5px + user-select: none + font-size: 30px + text-align: inherit + cursor: pointer + display: inline-block + .part1, .part2 + display: inline-block + .part1 + color: #03A9F4 + text-shadow: 2px 2px 1px #0059a0 + margin-right: 5px + .socialbtn + width: 28px + height: 28px + display: inline-block + line-height: 28px + color: #fff + font-size: 160% + border-radius: 100px + padding: 2px + margin: 5px + &#github + background-color: #000 + &#twitter + background-color: #03a9f4 + &#discord + background-color: #2C2F33 + .discordlogo + position: relative + top: 3px + background: url(https://icynet.eu/static/image/Discord-Logo-White.svg) + width: 22px + height: 22px + display: inline-block + i + position: relative + right: 1px + span.divider + color: #ddd + margin: 0 5px + cursor: default + +@media all and (max-width: 800px) + footer + .squeebot + margin: 0 + width: 150px + margin: auto + display: block + .copyright + margin-left: 0 diff --git a/LandingPage/static/css/style.styl b/LandingPage/static/css/style.styl new file mode 100644 index 0000000..326ace1 --- /dev/null +++ b/LandingPage/static/css/style.styl @@ -0,0 +1,58 @@ +body + background-color: #fff + font-family: "Open Sans", Helvetica + margin: 0 + padding: 0 + +.unibar + padding: 20px + border-bottom: 1px solid #ddd + box-shadow: 2px 2px 5px #9c9c9c + .logo + font-size: 200% + .userdata + display: inline-block + float: right + padding: 12px + +.wrapper + min-height: 100vh + +.show-promo + display: inline-block + width: 200px + text-align: center + margin: 5px + vertical-align: text-top + .artwork + max-width: 180px + max-height: 260px + +.blocklayout + .block + margin: 15px + box-shadow: 2px 2px 5px #9c9c9c + h1 + background-color: #f5f5f5 + border: 2px solid #d0d0d0 + border-bottom: 0 + padding: 8px + margin: 0 + .content + overflow: hidden + border: 2px solid #d0d0d0 + padding: 10px + &.columns + position: relative + .column + position: absolute + left: 0px + top: 0 + right: 0 + bottom: 0 + &.primary + width: 80% + &.smaller + width: 20% + right: 0 + left: auto diff --git a/LandingPage/templates/base.html b/LandingPage/templates/base.html new file mode 100644 index 0000000..fc9132d --- /dev/null +++ b/LandingPage/templates/base.html @@ -0,0 +1,37 @@ +{% load pipeline %} + + + + + + {% stylesheet 'style' %} + + {% block meta %} + + + + {% endblock %} + + {% block title %}Episodes.Community{% endblock %} + + + {% block unibar %} +
+ +
+ {% if request.session.user_id %} + logged in + {% else %} + Log in + {% endif %} +
+
+ {% endblock %} +
+ {% block content %}{% endblock %} +
+ {% block footer %} + + {% endblock %} + + diff --git a/LandingPage/templates/landing_page.html b/LandingPage/templates/landing_page.html index 3501747..5b94037 100644 --- a/LandingPage/templates/landing_page.html +++ b/LandingPage/templates/landing_page.html @@ -1,11 +1,37 @@ -{% for show in shows %} -
-

{{show.name}} [{{show.abbr}}]

-

{{show.description}}

- +{% extends "base.html" %} +{% block content %} +
+
+
+

Welcome to Episodes.Community!

+
+

Episodes.Community is a platform for sharing, watching and discussing your favorite shows!

+

Currently hosting {{ stats.shows }} shows, {{ stats.episodes }} submissions and {{ stats.boards }} discussions

+
+
+ +
+

Latest releases

+
+ {% if not recent %} Nothing to show {% endif %} + {% for show in recent %} + + + {{show.name}} + + {% endfor %} +
+
+
+ +
+
+

Donate

+
+

Donate to Icy Network to help us keep up our communities.

+ Click Here to Donate +
+
+
-{% endfor %} +{% endblock %} diff --git a/LandingPage/views.py b/LandingPage/views.py index 8fcd39a..c847595 100644 --- a/LandingPage/views.py +++ b/LandingPage/views.py @@ -10,6 +10,8 @@ import hashlib import json from .models import User from .models import Show +from .models import Submission +from .models import DiscussionBoard # Create your views here. # Redirect url should point to this view @@ -87,7 +89,12 @@ class LandingPage(TemplateView): def get_context_data(self, **kwargs): ctx = super().get_context_data() - ctx['shows'] = Show.objects.annotate(recency=Max('episodes__airdate')).order_by('-recency')[:8] + ctx['recent'] = Show.objects.annotate(recency=Max('episodes__airdate')).order_by('-recency')[:8] + ctx['stats'] = { + 'shows': Show.objects.count(), + 'episodes': Submission.objects.count(), + 'boards': DiscussionBoard.objects.count() + } return ctx diff --git a/requirements.txt b/requirements.txt index b52c65d..8371028 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Django==1.11.4 -Pillow=4.2.1 +Pillow==4.2.1 dj-database-url==0.4.2 +django-pipeline==1.6.13