diff --git a/.env.example b/.env.example index b62a12c..ee4e8d0 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,11 @@ DB_PASSWORD=${DB_PASSWORD:-postgres} DB_HOST=${DB_HOST:-db} DB_PORT=${DB_PORT:-5432} +# aws settings +AWS_STORAGE_BUCKET_NAME=${AWS_STORAGE_BUCKET_NAME} +AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} +AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + # Integration settings BROWSER_STACK_USER=${BROWSER_STACK_USER:-} BROWSER_ACCESS_KEY=${BROWSERSTACK_API_KEY:-} diff --git a/Dockerfile b/Dockerfile index 6391932..33a734a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -157,5 +157,7 @@ FROM runtime as prod HEALTHCHECK --start-period=10s --interval=5s --retries=20 --timeout=5s \ CMD curl --fail http://localhost:8000 || exit 1 # Pre-compile packages to .pyc (init speed gains) +USER root RUN python -c "import compileall; compileall.compile_path(maxlevels=10, quiet=1)" -CMD ["gunicorn", "hot_osm.wsgi:application"] +USER wagtail +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "hot_osm.wsgi:application"] diff --git a/app/events/__init__.py b/app/events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/events/admin.py b/app/events/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/events/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/events/apps.py b/app/events/apps.py new file mode 100644 index 0000000..923880a --- /dev/null +++ b/app/events/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EventsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.events' diff --git a/app/events/migrations/0001_initial.py b/app/events/migrations/0001_initial.py new file mode 100644 index 0000000..f8017ee --- /dev/null +++ b/app/events/migrations/0001_initial.py @@ -0,0 +1,53 @@ +# Generated by Django 4.2.7 on 2024-06-05 19:43 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ] + + operations = [ + migrations.CreateModel( + name='EventOwnerPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ('event_location_title', models.CharField(default='Event Location')), + ('join_event_title', models.CharField(default='Join This Event')), + ('rsvp_button_text', models.CharField(default='RSVP')), + ('more_events_title', models.CharField(default='More Events')), + ('view_all_events_text', models.CharField(default='View all Events')), + ('view_all_events_url', models.URLField(blank=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='IndividualEventPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ('start_date_time', models.DateTimeField()), + ('end_date_time', models.DateTimeField()), + ('intro', wagtail.fields.RichTextField(blank=True)), + ('extended_description', wagtail.fields.StreamField([('text_block', wagtail.blocks.RichTextBlock(features=['h1', 'h2', 'h3', 'h4', 'bold', 'italic', 'link', 'ol', 'ul', 'hr', 'document-link', 'image', 'embed', 'code', 'blockquote']))], null=True, use_json_field=True)), + ('event_location', models.CharField(blank=True)), + ('rsvp_description', wagtail.fields.RichTextField(blank=True)), + ('rsvp_link', models.URLField(blank=True)), + ('image', models.ForeignKey(blank=True, help_text='Image to represent the event', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/events/migrations/0002_individualeventpage_more_events_and_more.py b/app/events/migrations/0002_individualeventpage_more_events_and_more.py new file mode 100644 index 0000000..8069bdd --- /dev/null +++ b/app/events/migrations/0002_individualeventpage_more_events_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2024-06-05 20:25 + +from django.db import migrations, models +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='individualeventpage', + name='more_events', + field=wagtail.fields.StreamField([('event', wagtail.blocks.PageChooserBlock(page_type=['events.IndividualEventPage']))], blank=True, null=True, use_json_field=True), + ), + migrations.AlterField( + model_name='individualeventpage', + name='rsvp_link', + field=models.URLField(blank=True, help_text='If both RSVP Description and Link are empty, the RSVP section will be hidden.'), + ), + ] diff --git a/app/events/migrations/0003_eventownerpage_event_read_more_text_and_more.py b/app/events/migrations/0003_eventownerpage_event_read_more_text_and_more.py new file mode 100644 index 0000000..355e00f --- /dev/null +++ b/app/events/migrations/0003_eventownerpage_event_read_more_text_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.7 on 2024-06-05 22:09 + +from django.db import migrations, models +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0002_individualeventpage_more_events_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='eventownerpage', + name='event_read_more_text', + field=models.CharField(default='Read more'), + ), + migrations.AlterField( + model_name='individualeventpage', + name='rsvp_description', + field=wagtail.fields.RichTextField(blank=True, help_text='If this field is empty, the RSVP description will not appear.'), + ), + migrations.AlterField( + model_name='individualeventpage', + name='rsvp_link', + field=models.URLField(blank=True, help_text='If this field is empty, the RSVP button will not appear. If both RSVP Description and Link are empty, the RSVP section will be hidden.'), + ), + ] diff --git a/app/events/migrations/__init__.py b/app/events/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/events/models.py b/app/events/models.py new file mode 100644 index 0000000..47a1d1c --- /dev/null +++ b/app/events/models.py @@ -0,0 +1,79 @@ +from django.db import models + +from wagtail.models import Page +from wagtail.fields import RichTextField, StreamField +from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PageChooserPanel +from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock +from modelcluster.fields import ParentalKey, ParentalManyToManyField + + +class EventOwnerPage(Page): + max_count = 1 + + event_location_title = models.CharField(default="Event Location") + join_event_title = models.CharField(default="Join This Event") + rsvp_button_text = models.CharField(default="RSVP") + more_events_title = models.CharField(default="More Events") + view_all_events_text = models.CharField(default="View all Events") + view_all_events_url = models.URLField(blank=True) + event_read_more_text = models.CharField(default="Read more") + + content_panels = Page.content_panels + [ + FieldPanel('event_location_title'), + FieldPanel('join_event_title'), + FieldPanel('rsvp_button_text'), + FieldPanel('more_events_title'), + FieldPanel('view_all_events_text'), + FieldPanel('view_all_events_url'), + FieldPanel('event_read_more_text'), + ] + + +class IndividualEventPage(Page): + parent_page_type = [ + 'projects.ProjectOwnerPage' + ] + + start_date_time = models.DateTimeField() + end_date_time = models.DateTimeField() + + image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Image to represent the event" + ) + intro = RichTextField(blank=True) + extended_description = StreamField([ + ('text_block', RichTextBlock(features=[ + 'h1', 'h2', 'h3', 'h4', 'bold', 'italic', 'link', 'ol', 'ul', 'hr', 'document-link', 'image', 'embed', 'code', 'blockquote' + ])) + ], use_json_field=True, null=True) + + event_location = models.CharField(blank=True) + rsvp_description = RichTextField(blank=True, help_text="If this field is empty, the RSVP description will not appear.") + rsvp_link = models.URLField(blank=True, help_text="If this field is empty, the RSVP button will not appear. If both RSVP Description and Link are empty, the RSVP section will be hidden.") + + more_events = StreamField([ + ('event', PageChooserBlock(page_type="events.IndividualEventPage")) + ], use_json_field=True, null=True, blank=True) + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel('start_date_time'), + FieldPanel('end_date_time'), + ], heading="Date and Time"), + MultiFieldPanel([ + FieldPanel('image'), + FieldPanel('intro'), + FieldPanel('extended_description'), + ], heading="Body"), + MultiFieldPanel([ + FieldPanel('event_location'), + FieldPanel('rsvp_description'), + FieldPanel('rsvp_link'), + FieldPanel('more_events'), + ], heading="Sidebar") + ] diff --git a/app/events/templates/events/individual_event_page.html b/app/events/templates/events/individual_event_page.html new file mode 100644 index 0000000..de51588 --- /dev/null +++ b/app/events/templates/events/individual_event_page.html @@ -0,0 +1,75 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-individualmappinghubpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} +
+ {{ page.start_date_time }} – {% if page.start_date_time.date == page.end_date_time.date %}{{ page.end_date_time.time }} {% else %} {{page.end_date_time}} {% endif %} +
++ {{ event.start_date_time.date }} +
++ {{event.start_date_time.time}} – {{ event.end_date_time.time }} +
+ {% else %} ++ {{event.start_date_time}} +
+–
++ {{event.end_date_time}} +
+ {% endif %} +{{event.title}}
+