diff options
Diffstat (limited to 'app/classes')
-rw-r--r-- | app/classes/__init__.py | 0 | ||||
-rw-r--r-- | app/classes/admin.py | 45 | ||||
-rw-r--r-- | app/classes/migrations/0001_initial.py | 57 | ||||
-rw-r--r-- | app/classes/migrations/0002_alter_class_requires.py | 18 | ||||
-rw-r--r-- | app/classes/migrations/0003_auto_20220109_2043.py | 25 | ||||
-rw-r--r-- | app/classes/migrations/0004_rename_name_class_title.py | 18 | ||||
-rw-r--r-- | app/classes/migrations/0005_auto_20220109_2100.py | 23 | ||||
-rw-r--r-- | app/classes/migrations/0006_auto_20220109_2104.py | 28 | ||||
-rw-r--r-- | app/classes/migrations/0007_session_status.py | 18 | ||||
-rw-r--r-- | app/classes/migrations/0008_class_subtitle.py | 19 | ||||
-rw-r--r-- | app/classes/migrations/__init__.py | 0 | ||||
-rw-r--r-- | app/classes/models.py | 96 | ||||
-rw-r--r-- | app/classes/templates/classes/class_detail.html | 11 | ||||
-rw-r--r-- | app/classes/templates/classes/class_list.html | 43 | ||||
-rw-r--r-- | app/classes/urls.py | 24 | ||||
-rw-r--r-- | app/classes/views.py | 20 |
16 files changed, 445 insertions, 0 deletions
diff --git a/app/classes/__init__.py b/app/classes/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/classes/__init__.py diff --git a/app/classes/admin.py b/app/classes/admin.py new file mode 100644 index 0000000..5fcca4b --- /dev/null +++ b/app/classes/admin.py @@ -0,0 +1,45 @@ +from django.contrib import admin +from django import forms +from django.contrib.gis.admin import OSMGeoAdmin +from django.contrib.contenttypes.admin import GenericStackedInline + +from utils.widgets import AdminImageWidget, LGEntryForm +from .models import Class, Session, ClassMedia + + +@admin.register(Class) +class ClassAdmin(admin.ModelAdmin): + list_display = ('title', 'session') + search_fields = ['title', 'description'] + prepopulated_fields = {"slug": ('title',)} + list_filter = ('session',) + filter_horizontal = ('uploads',) + + class Media: + js = ('image-loader.js', 'product-loader.js', 'next-prev-links.js') + css = { + "all": ("my_styles.css",) + } + + +@admin.register(Session) +class SessionAdmin(admin.ModelAdmin): + list_display = ('title','date_start','date_end' ) + prepopulated_fields = {"slug": ('title',)} + + class Media: + js = ('image-loader.js', 'product-loader.js', 'next-prev-links.js') + css = { + "all": ("my_styles.css",) + } + + +@admin.register(ClassMedia) +class ClassMediaAdmin(admin.ModelAdmin): + list_display = ('title','file' ) + + class Media: + js = ('image-loader.js', 'product-loader.js', 'next-prev-links.js') + css = { + "all": ("my_styles.css",) + } diff --git a/app/classes/migrations/0001_initial.py b/app/classes/migrations/0001_initial.py new file mode 100644 index 0000000..b533aaf --- /dev/null +++ b/app/classes/migrations/0001_initial.py @@ -0,0 +1,57 @@ +# Generated by Django 3.2.8 on 2022-01-09 19:25 + +import classes.models +import datetime +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ClassMedia', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('date_created', models.DateTimeField(default=datetime.datetime.now)), + ('file', models.FileField(blank=True, null=True, upload_to=classes.models.get_upload_path)), + ], + ), + migrations.CreateModel( + name='Session', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('date_start', models.DateField(verbose_name='Start Date')), + ('date_end', models.DateField(verbose_name='End Date')), + ('slug', models.SlugField()), + ], + options={ + 'ordering': ('-date_start',), + 'get_latest_by': 'date_start', + }, + ), + migrations.CreateModel( + name='Class', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('description', models.TextField()), + ('requires', models.TextField(verbose_name='If previous classwork is required, list prerequisites here')), + ('slug', models.SlugField()), + ('date_created', models.DateTimeField(default=datetime.datetime.now)), + ('session', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='classes.session')), + ('uploads', models.ManyToManyField(blank=True, to='classes.ClassMedia')), + ], + options={ + 'ordering': ('-date_created',), + 'get_latest_by': 'date_created', + }, + ), + ] diff --git a/app/classes/migrations/0002_alter_class_requires.py b/app/classes/migrations/0002_alter_class_requires.py new file mode 100644 index 0000000..8febb99 --- /dev/null +++ b/app/classes/migrations/0002_alter_class_requires.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.8 on 2022-01-09 19:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='class', + name='requires', + field=models.TextField(blank=True, null=True, verbose_name='If previous classwork is required, list prerequisites here'), + ), + ] diff --git a/app/classes/migrations/0003_auto_20220109_2043.py b/app/classes/migrations/0003_auto_20220109_2043.py new file mode 100644 index 0000000..cd25dcd --- /dev/null +++ b/app/classes/migrations/0003_auto_20220109_2043.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.8 on 2022-01-09 20:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0002_alter_class_requires'), + ] + + operations = [ + migrations.AddField( + model_name='class', + name='number_of_classes', + field=models.IntegerField(default=8), + preserve_default=False, + ), + migrations.AddField( + model_name='class', + name='price', + field=models.FloatField(default=225), + preserve_default=False, + ), + ] diff --git a/app/classes/migrations/0004_rename_name_class_title.py b/app/classes/migrations/0004_rename_name_class_title.py new file mode 100644 index 0000000..00ac456 --- /dev/null +++ b/app/classes/migrations/0004_rename_name_class_title.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.8 on 2022-01-09 20:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0003_auto_20220109_2043'), + ] + + operations = [ + migrations.RenameField( + model_name='class', + old_name='name', + new_name='title', + ), + ] diff --git a/app/classes/migrations/0005_auto_20220109_2100.py b/app/classes/migrations/0005_auto_20220109_2100.py new file mode 100644 index 0000000..b5bd825 --- /dev/null +++ b/app/classes/migrations/0005_auto_20220109_2100.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.8 on 2022-01-09 21:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0004_rename_name_class_title'), + ] + + operations = [ + migrations.RenameField( + model_name='classmedia', + old_name='name', + new_name='title', + ), + migrations.RenameField( + model_name='session', + old_name='name', + new_name='title', + ), + ] diff --git a/app/classes/migrations/0006_auto_20220109_2104.py b/app/classes/migrations/0006_auto_20220109_2104.py new file mode 100644 index 0000000..d25ead2 --- /dev/null +++ b/app/classes/migrations/0006_auto_20220109_2104.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.8 on 2022-01-09 21:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0005_auto_20220109_2100'), + ] + + operations = [ + migrations.AddField( + model_name='class', + name='class_days', + field=models.IntegerField(choices=[(0, 'Mon/Wed'), (1, 'Tue/Thur')], default=0), + ), + migrations.AddField( + model_name='session', + name='length', + field=models.PositiveIntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name='class', + name='number_of_classes', + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/app/classes/migrations/0007_session_status.py b/app/classes/migrations/0007_session_status.py new file mode 100644 index 0000000..d01d944 --- /dev/null +++ b/app/classes/migrations/0007_session_status.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.8 on 2022-01-09 21:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0006_auto_20220109_2104'), + ] + + operations = [ + migrations.AddField( + model_name='session', + name='status', + field=models.IntegerField(choices=[(0, 'Open'), (1, 'Closed')], default=0), + ), + ] diff --git a/app/classes/migrations/0008_class_subtitle.py b/app/classes/migrations/0008_class_subtitle.py new file mode 100644 index 0000000..1d572b0 --- /dev/null +++ b/app/classes/migrations/0008_class_subtitle.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.8 on 2022-01-09 22:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('classes', '0007_session_status'), + ] + + operations = [ + migrations.AddField( + model_name='class', + name='subtitle', + field=models.CharField(default='some text', max_length=200), + preserve_default=False, + ), + ] diff --git a/app/classes/migrations/__init__.py b/app/classes/migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/classes/migrations/__init__.py diff --git a/app/classes/models.py b/app/classes/models.py new file mode 100644 index 0000000..b10c863 --- /dev/null +++ b/app/classes/models.py @@ -0,0 +1,96 @@ +import datetime +import os + +from django.dispatch import receiver +from django.contrib.gis.db import models +from django.db.models.signals import post_save +from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey +from django.contrib.contenttypes.models import ContentType +from django.contrib.sites.models import Site +from django.urls import reverse +from django.utils.functional import cached_property +from django.apps import apps +from django.conf import settings +from django.contrib.sitemaps import Sitemap +from django import forms + +import urllib.request +import urllib.parse +import urllib.error +from django_gravatar.helpers import get_gravatar_url, has_gravatar, calculate_gravatar_hash +from django_comments.signals import comment_was_posted +from django_comments.models import Comment +from django_comments.moderation import CommentModerator, moderator + +from taggit.managers import TaggableManager + +from utils.util import render_images, render_products, parse_video, markdown_to_html, extract_main_image + + +def get_upload_path(self, filename): + return "files/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename) + + +class Session(models.Model): + title = models.CharField(max_length=200) + date_start = models.DateField('Start Date') + date_end = models.DateField('End Date') + slug = models.SlugField() + length = models.PositiveIntegerField(blank=True, null=True) + STATUS = ( + (0, 'Open'), + (1, 'Closed'), + ) + status = models.IntegerField(choices=STATUS, default=0) + + class Meta: + ordering = ('-date_start',) + get_latest_by = 'date_start' + + def __str__(self): + return self.title + + def get_absolute_url(self): + return reverse('classes:session-detail', kwargs={"year": self.start_date.year, "month": self.start_date.strftime("%m"), "slug": self.slug}) + + # save length from date + + +class ClassMedia(models.Model): + title = models.CharField(max_length=200) + date_created = models.DateTimeField(default=datetime.datetime.now) + file = models.FileField(blank=True, null=True, upload_to=get_upload_path) + + def __str__(self): + return self.title + + +class Class(models.Model): + title = models.CharField(max_length=200) + subtitle = models.CharField(max_length=200) + description = models.TextField() + requires = models.TextField('If previous classwork is required, list prerequisites here', null=True, blank=True,) + session = models.ForeignKey(Session, blank=True, null=True, on_delete=models.SET_NULL) + slug = models.SlugField() + uploads = models.ManyToManyField(ClassMedia, blank=True) + date_created = models.DateTimeField(default=datetime.datetime.now) + number_of_classes = models.IntegerField(blank=True, null=True) + CLASS_DAYS = ( + (0, 'Mon/Wed'), + (1, 'Tue/Thur'), + ) + class_days = models.IntegerField(choices=CLASS_DAYS, default=0) + price = models.FloatField() + + class Meta: + ordering = ('-date_created',) + get_latest_by = 'date_created' + + def __str__(self): + return self.title + + def get_absolute_url(self): + return reverse('classes:detail', kwargs={"slug": self.slug}) + + def save(self, *args, **kwargs): + super(Class, self).save(*args, **kwargs) diff --git a/app/classes/templates/classes/class_detail.html b/app/classes/templates/classes/class_detail.html new file mode 100644 index 0000000..50ae63f --- /dev/null +++ b/app/classes/templates/classes/class_detail.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% block primary %} +<main> +<article> + <h2><a href="{{object.get_absolute_url}}">{{object.title|widont|smartypants}}</a></h2> + <h4>{{object.description|safe|widont|smartypants}}</h4> + +</article> +</main> +{% endblock %} diff --git a/app/classes/templates/classes/class_list.html b/app/classes/templates/classes/class_list.html new file mode 100644 index 0000000..fa1267c --- /dev/null +++ b/app/classes/templates/classes/class_list.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% load get_next %} +{% load html5_datetime %} +{% load pagination_tags %} +{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %} +{% block primary %} +<main role="main" class="archive-wrapper"> + <div class="archive-intro"> + <h2 class="archive-hed">Classes</h2> + <p>More information coming soon.</p> + </div> + {% comment %} + {% autopaginate object_list 24 %} + <ul class="archive-list">{% for object in object_list %} + <li class="h-entry hentry archive-list-card" itemscope itemType="http://schema.org/Article"> + {% if object.featured_image %}<a href="{{object.get_absolute_url}}" class="u-url"> + <div class="circle-img-wrapper"><img src="{{object.featured_image.get_thumbnail_url}}" alt="{{object.featured_image.alt}}" class="u-photo" /></div>{%endif%} + <span class="date dt-published card-smcaps">{{object.pub_date|date:"F Y"}}</span> + <a href="{{object.get_absolute_url}}"> + <h2 class="card-hed">{{object.title|safe|smartypants|widont}}</h2> + <p class="card-lede">{{object.subtitle}}</p> + <p class="p-summary">{{object.description}}</p> + {% if object.session.status == 0 %} + <p>Now Enrolling for {{object.session.title}} <br />({{object.number_of_classes}} classes every {{object.get_class_days_display}}, {{object.session.date_start}} - {{object.session.date_end}})</p> + {% else %} + <p>This class is not currently offered, but if you're interested please email me about setting up a future session.</p> + {% endif %} + {% if object.requires %} + <p>Prerequisites: {{object.requires}}</p> + {% endif %} + </a> + </li> + {%endfor%}</ul> + {%endcomment%} + </main> + {%comment%} + <nav aria-label="page navigation" class="pagination"> + {% paginate %} + </nav> + {%endcomment%} +</main> +{% endblock %} diff --git a/app/classes/urls.py b/app/classes/urls.py new file mode 100644 index 0000000..ac9cce5 --- /dev/null +++ b/app/classes/urls.py @@ -0,0 +1,24 @@ +from django.urls import path, re_path + +from . import views + +app_name = "classes" + +urlpatterns = [ + path( + r'<str:slug>', + views.ClassDetailView.as_view(), + name="detail" + ), + path( + r'', + views.ClassListView.as_view(), + {'page': 1}, + name="list" + ), + path( + r'<page>/', + views.ClassListView.as_view(), + name="list" + ), +] diff --git a/app/classes/views.py b/app/classes/views.py new file mode 100644 index 0000000..620e5db --- /dev/null +++ b/app/classes/views.py @@ -0,0 +1,20 @@ +from utils.views import LuxDetailView +from django.views.generic import DetailView, ListView +from utils.views import PaginatedListView, LuxDetailView + +from .models import Class + + +class ClassDetailView(LuxDetailView): + model = Class + +class ClassListView(PaginatedListView): + model = Class + + def get_context_data(self, **kwargs): + ''' + Add breadcrumb path + ''' + context = super(ClassListView, self).get_context_data(**kwargs) + context['breadcrumbs'] = ("classes",) + return context |