From b9aee578c39a5589f141a46c683d886f8b081746 Mon Sep 17 00:00:00 2001 From: Ryan Westfall Date: Tue, 15 Apr 2025 12:18:03 -0500 Subject: [PATCH] redesign proto --- requirements.txt | 17 +- scha/asgi.py | 2 +- scha/settings.py | 90 ++-- scha/urls.py | 9 +- scha/wsgi.py | 2 +- schasite/admin.py | 238 ++++++---- schasite/apps.py | 4 +- schasite/forms.py | 86 +++- schasite/migrations/0001_initial.py | 209 ++++++--- .../0002_alter_membership_children.py | 8 +- ...bershipcommittee_block_captain_and_more.py | 54 +-- ...004_alter_membershipperson_phone_number.py | 10 +- .../migrations/0005_membershipservices.py | 59 ++- ...0006_calendareventaddressmodel_and_more.py | 38 +- schasite/migrations/0007_payments.py | 35 +- .../migrations/0008_alter_payments_date.py | 12 +- .../0009_schaofficer_alter_payments_date.py | 40 ++ schasite/models.py | 69 ++- schasite/static/css/style2.css | 47 ++ schasite/templates/schasite/about_us2.html | 276 ++++++++++++ schasite/templates/schasite/base2.html | 90 ++++ schasite/templates/schasite/calendar2.html | 202 +++++++++ schasite/templates/schasite/dues2.html | 230 ++++++++++ schasite/templates/schasite/index2.html | 208 +++++++++ .../templates/schasite/membership_form2.html | 414 ++++++++++++++++++ schasite/templates/schasite/newsletters2.html | 9 + schasite/templates/schasite/scha_board2.html | 149 +++++++ .../templates/schasite/useful_links2.html | 290 ++++++++++++ schasite/urls.py | 15 +- schasite/views.py | 384 ++++++++++++---- 30 files changed, 2899 insertions(+), 397 deletions(-) create mode 100644 schasite/migrations/0009_schaofficer_alter_payments_date.py create mode 100644 schasite/static/css/style2.css create mode 100644 schasite/templates/schasite/about_us2.html create mode 100644 schasite/templates/schasite/base2.html create mode 100644 schasite/templates/schasite/calendar2.html create mode 100644 schasite/templates/schasite/dues2.html create mode 100644 schasite/templates/schasite/index2.html create mode 100644 schasite/templates/schasite/membership_form2.html create mode 100644 schasite/templates/schasite/newsletters2.html create mode 100644 schasite/templates/schasite/scha_board2.html create mode 100644 schasite/templates/schasite/useful_links2.html diff --git a/requirements.txt b/requirements.txt index 602b2e9..57f4917 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,13 @@ -stripe -django -django-adminplus -django-recaptcha \ No newline at end of file +asgiref==3.8.1 +certifi==2025.1.31 +charset-normalizer==3.4.1 +Django==5.2 +django-phonenumber-field==8.1.0 +django-recaptcha==4.1.0 +idna==3.10 +phonenumbers==9.0.3 +requests==2.32.3 +sqlparse==0.5.3 +stripe==12.0.0 +typing_extensions==4.13.2 +urllib3==2.4.0 diff --git a/scha/asgi.py b/scha/asgi.py index ffcdfcd..fbfc5bf 100644 --- a/scha/asgi.py +++ b/scha/asgi.py @@ -11,6 +11,6 @@ import os from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'scha.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "scha.settings") application = get_asgi_application() diff --git a/scha/settings.py b/scha/settings.py index e349dc8..1891b62 100644 --- a/scha/settings.py +++ b/scha/settings.py @@ -20,7 +20,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-0&6)5#t(wghsn$q7pg#s!x+_!s_y#labf6dh*8q%34q25iuag*' +SECRET_KEY = "django-insecure-0&6)5#t(wghsn$q7pg#s!x+_!s_y#labf6dh*8q%34q25iuag*" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -31,55 +31,55 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ - 'schasite.apps.SchasiteConfig', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'phonenumber_field', - 'django_recaptcha', + "schasite.apps.SchasiteConfig", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "phonenumber_field", + "django_recaptcha", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'scha.urls' +ROOT_URLCONF = "scha.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'scha.wsgi.application' +WSGI_APPLICATION = "scha.wsgi.application" # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } @@ -89,16 +89,16 @@ DATABASES = { AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -106,9 +106,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -118,16 +118,18 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ -STATIC_URL = 'static/' +STATIC_URL = "static/" # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -STRIPE_PUBLISHABLE_KEY = 'pk_test_51OxENZDV0RPXOyxGkZnncLFbpVoQq6qxUSN08BPDTpHjrm2UTtvOrBG2A2IQhX3oxdYd6amGaci00SKchYZ5DUUN00jTBzhh62' -STRIPE_SECRET_KEY = 'sk_test_51OxENZDV0RPXOyxGkULVr0MvVvXgNWsKjWiP54a9ls02LgsgXnzEwP0IQ0VjvP4Wt4RrPx1FvzHSbLvChQGOKvv800Ui0NBvIA' -STRIPE_ENDPOINT_SECRET = 'whsec_a38b2d115b64d86713397e2718e2d42e5d263139dfbac6c0badc6f9ca8f72557' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +STRIPE_PUBLISHABLE_KEY = "pk_test_51OxENZDV0RPXOyxGkZnncLFbpVoQq6qxUSN08BPDTpHjrm2UTtvOrBG2A2IQhX3oxdYd6amGaci00SKchYZ5DUUN00jTBzhh62" +STRIPE_SECRET_KEY = "sk_test_51OxENZDV0RPXOyxGkULVr0MvVvXgNWsKjWiP54a9ls02LgsgXnzEwP0IQ0VjvP4Wt4RrPx1FvzHSbLvChQGOKvv800Ui0NBvIA" +STRIPE_ENDPOINT_SECRET = ( + "whsec_a38b2d115b64d86713397e2718e2d42e5d263139dfbac6c0badc6f9ca8f72557" +) # Recaptcha Stuff -RECAPTCHA_PUBLIC_KEY = '6LesfrkpAAAAAGJ5vYp4KuuGcyfk70HkihCwp3d3' -RECAPTCHA_PRIVATE_KEY = '6LesfrkpAAAAABCcDGli5cZiq1hfS0lfRiXg0mlI' \ No newline at end of file +RECAPTCHA_PUBLIC_KEY = "6LesfrkpAAAAAGJ5vYp4KuuGcyfk70HkihCwp3d3" +RECAPTCHA_PRIVATE_KEY = "6LesfrkpAAAAABCcDGli5cZiq1hfS0lfRiXg0mlI" diff --git a/scha/urls.py b/scha/urls.py index a10a8f2..611715b 100644 --- a/scha/urls.py +++ b/scha/urls.py @@ -14,6 +14,7 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.contrib import admin from django.urls import include, path from django.conf.urls.static import static @@ -23,8 +24,8 @@ from schasite.views import stripe_cancelled, stripe_success, stripe_webhook urlpatterns = [ path("schasite/", include("schasite.urls")), - path('success/', stripe_success), - path('cancelled/', stripe_cancelled), - path('webhook/', stripe_webhook), - path('admin/', admin.site.urls), + path("success/", stripe_success), + path("cancelled/", stripe_cancelled), + path("webhook/", stripe_webhook), + path("admin/", admin.site.urls), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/scha/wsgi.py b/scha/wsgi.py index 58831fc..d60a827 100644 --- a/scha/wsgi.py +++ b/scha/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'scha.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "scha.settings") application = get_wsgi_application() diff --git a/schasite/admin.py b/schasite/admin.py index c04bfdd..24adf24 100644 --- a/schasite/admin.py +++ b/schasite/admin.py @@ -1,192 +1,250 @@ from django.contrib import admin -from .models import UsefulLinks, Membership,CalendarEvent, MembershipServices, AddressModel1, MembershipPerson, MembershipCommittee, CalendarEventAddressModel, Payments +from .models import ( + UsefulLinks, + Membership, + CalendarEvent, + MembershipServices, + AddressModel1, + MembershipPerson, + MembershipCommittee, + CalendarEventAddressModel, + Payments, + SCHAOfficer, +) from django.http import HttpResponse from datetime import datetime from .forms import PaymentImport + # Register your models here. + class UsefulLinksAdmin(admin.ModelAdmin): list_display = ["name", "url"] + class MembershipAddressInline(admin.TabularInline): model = AddressModel1 extra = 1 - readonly_fields = ('id',) + readonly_fields = ("id",) + class MembershipPersonInline(admin.TabularInline): model = MembershipPerson extra = 1 - readonly_fields = ('id',) + readonly_fields = ("id",) + class MembershipCommiteeInline(admin.TabularInline): model = MembershipCommittee extra = 1 - readonly_fields = ('id',) + readonly_fields = ("id",) + class MembershipServicesInline(admin.TabularInline): model = MembershipServices extra = 1 - readonly_fields = ('id',) + readonly_fields = ("id",) + def download_csv_by_members(modelAdmin, request, queryset): - import csv + import csv import io as StringIO + def stream_csv(queryset): csvfile = StringIO.StringIO() writer = csv.writer(csvfile) - writer.writerow([ - 'address_1', - 'city', - 'state', - 'zip_code', - 'first_name', - 'last_name', - 'email', - 'phone_number' - ]) + writer.writerow( + [ + "address_1", + "city", + "state", + "zip_code", + "first_name", + "last_name", + "email", + "phone_number", + ] + ) for q in queryset: - people = [item for item in MembershipPerson.objects.filter(membership_id=q.id)] + people = [ + item for item in MembershipPerson.objects.filter(membership_id=q.id) + ] for person in people: - writer.writerow([ - q.addressmodel1.address_1, - q.addressmodel1.city, - q.addressmodel1.state, - q.addressmodel1.zip_code, - person.first_name, - person.last_name, - person.email, - person.phone_number - ]) + writer.writerow( + [ + q.addressmodel1.address_1, + q.addressmodel1.city, + q.addressmodel1.state, + q.addressmodel1.zip_code, + person.first_name, + person.last_name, + person.email, + person.phone_number, + ] + ) yield csvfile.getvalue() - + now = datetime.now() filename = now.strftime("%Y_%m_%d_%H_%M_%S") + "_scha_member_by_member.csv" response = HttpResponse(stream_csv(queryset), content_type="text/csv") - response['Content-Disposition'] = "attachment; filename={}".format(filename) + response["Content-Disposition"] = "attachment; filename={}".format(filename) return response - + def download_csv_by_address(modeladmin, request, queryset): import csv import io as StringIO + def stream_csv(queryset): csvfile = StringIO.StringIO() writer = csv.writer(csvfile) - writer.writerow(['address_1', - "city", - "state", - "zip_code", - "person_1_email", - "person_1_phone", - "person_1_first_name", - "person_1_last_name", - "person_2_email", - "person_2_phone", - "person_2_first_name", - "person_2_last_name"]) - + writer.writerow( + [ + "address_1", + "city", + "state", + "zip_code", + "person_1_email", + "person_1_phone", + "person_1_first_name", + "person_1_last_name", + "person_2_email", + "person_2_phone", + "person_2_first_name", + "person_2_last_name", + ] + ) + for q in queryset: - people = [item for item in MembershipPerson.objects.filter(membership_id=q.id)] - writer.writerow([ - q.addressmodel1.address_1, - q.addressmodel1.city, - q.addressmodel1.state, - q.addressmodel1.zip_code, - people[0].email if len(people) > 0 else "", - people[0].phone_number if len(people) > 0 else "", - people[0].first_name if len(people) > 0 else "", - people[0].last_name if len(people) > 0 else "", - people[1].email if len(people) > 1 else "", - people[1].phone_number if len(people) > 1 else "", - people[1].first_name if len(people) > 1 else "", - people[1].last_name if len(people) > 1 else "", - ]) + people = [ + item for item in MembershipPerson.objects.filter(membership_id=q.id) + ] + writer.writerow( + [ + q.addressmodel1.address_1, + q.addressmodel1.city, + q.addressmodel1.state, + q.addressmodel1.zip_code, + people[0].email if len(people) > 0 else "", + people[0].phone_number if len(people) > 0 else "", + people[0].first_name if len(people) > 0 else "", + people[0].last_name if len(people) > 0 else "", + people[1].email if len(people) > 1 else "", + people[1].phone_number if len(people) > 1 else "", + people[1].first_name if len(people) > 1 else "", + people[1].last_name if len(people) > 1 else "", + ] + ) yield csvfile.getvalue() now = datetime.now() filename = now.strftime("%Y_%m_%d_%H_%M_%S") + "_scha_member_by_address.csv" response = HttpResponse(stream_csv(queryset), content_type="text/csv") - response['Content-Disposition'] = "attachment; filename={}".format(filename) + response["Content-Disposition"] = "attachment; filename={}".format(filename) return response + class MembershipAdmin(admin.ModelAdmin): - inlines = [MembershipAddressInline, MembershipPersonInline, MembershipCommiteeInline, MembershipServicesInline] - actions=[download_csv_by_address, download_csv_by_members] + inlines = [ + MembershipAddressInline, + MembershipPersonInline, + MembershipCommiteeInline, + MembershipServicesInline, + ] + actions = [download_csv_by_address, download_csv_by_members] + class CalendarEventAddressInline(admin.TabularInline): model = CalendarEventAddressModel extra = 1 - readonly_fields = ('id',) + readonly_fields = ("id",) + class CalendarEventAdmin(admin.ModelAdmin): inlines = [CalendarEventAddressInline] - list_display = ["event_name", "start_date", "end_date", "coordinator_email", "event_link_name"] + list_display = [ + "event_name", + "start_date", + "end_date", + "coordinator_email", + "event_link_name", + ] + class AddressModelAdmin(admin.ModelAdmin): pass + class MembershipPersonAdmin(admin.ModelAdmin): pass + class MembershipCommitteeAdmin(admin.ModelAdmin): pass + class MembershipServicesAdmin(admin.ModelAdmin): pass + class CalendarEventAddressModelAdmin(admin.ModelAdmin): pass + def download_payments(modelAdmin, request, queryset): - import csv + import csv import io as StringIO + def stream_payment_csv(queryset): csvfile = StringIO.StringIO() writer = csv.writer(csvfile) - writer.writerow([ - 'email', - 'date', - 'status', - 'first_name', - 'last_name', - 'phone_number' - ]) + writer.writerow( + ["email", "date", "status", "first_name", "last_name", "phone_number"] + ) for q in queryset: - first_name="" + first_name = "" last_name = "" phone_number = "" if q.person: first_name = q.person.first_name if q.person.first_name else "" last_name = q.person.last_name if q.person.last_name else "" phone_number = q.person.phone_number if q.person.phone_number else "" - writer.writerow([ - q.email, - q.date, - q.status, - first_name, - last_name, - phone_number, - ]) + writer.writerow( + [ + q.email, + q.date, + q.status, + first_name, + last_name, + phone_number, + ] + ) yield csvfile.getvalue() - + now = datetime.now() filename = now.strftime("%Y_%m_%d_%H_%M_%S") + "_scha_payments_by_member.csv" response = HttpResponse(stream_payment_csv(queryset), content_type="text/csv") - response['Content-Disposition'] = "attachment; filename={}".format(filename) + response["Content-Disposition"] = "attachment; filename={}".format(filename) return response + class PaymentsAdmin(admin.ModelAdmin): list_display = ["date", "status", "email"] - search_fields = ['email'] - actions=[download_payments] + search_fields = ["email"] + actions = [download_payments] form = PaymentImport +class SCHAOfficerAdmin(admin.ModelAdmin): + list_display = ["position", "name", "email"] + admin.site.register(UsefulLinks, UsefulLinksAdmin) admin.site.register(Membership, MembershipAdmin) admin.site.register(CalendarEvent, CalendarEventAdmin) -admin.site.register(AddressModel1, AddressModelAdmin) +admin.site.register(AddressModel1, AddressModelAdmin) admin.site.register(MembershipPerson, MembershipPersonAdmin) -admin.site.register(MembershipCommittee, MembershipCommitteeAdmin) -admin.site.register(MembershipServices, MembershipServicesAdmin) -admin.site.register(CalendarEventAddressModel, CalendarEventAddressModelAdmin) -admin.site.register(Payments, PaymentsAdmin) \ No newline at end of file +admin.site.register(MembershipCommittee, MembershipCommitteeAdmin) +admin.site.register(MembershipServices, MembershipServicesAdmin) +admin.site.register(CalendarEventAddressModel, CalendarEventAddressModelAdmin) +admin.site.register(Payments, PaymentsAdmin) +admin.site.register(SCHAOfficer, SCHAOfficerAdmin) + diff --git a/schasite/apps.py b/schasite/apps.py index e93d8f0..2b87661 100644 --- a/schasite/apps.py +++ b/schasite/apps.py @@ -2,5 +2,5 @@ from django.apps import AppConfig class SchasiteConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'schasite' + default_auto_field = "django.db.models.BigAutoField" + name = "schasite" diff --git a/schasite/forms.py b/schasite/forms.py index fbca79a..eb626b5 100644 --- a/schasite/forms.py +++ b/schasite/forms.py @@ -1,8 +1,15 @@ from django import forms from django.forms import ModelForm -from .models import Membership, AddressModel1, MembershipPerson, MembershipCommittee, MembershipServices +from .models import ( + Membership, + AddressModel1, + MembershipPerson, + MembershipCommittee, + MembershipServices, +) from phonenumber_field.formfields import PhoneNumberField from django.core.exceptions import ValidationError + # from django_recaptcha.fields import ReCaptchaField # from django.conf import settings # from django_recaptcha.widgets import ReCaptchaV3 @@ -19,45 +26,81 @@ from django.core.exceptions import ValidationError # ) + class ChildrenForm(ModelForm): class Meta: model = Membership fields = ["children"] + class AddressForm(ModelForm): class Meta: model = AddressModel1 - fields = ["address_1","address_2","city","state","zip_code"] + fields = ["address_1", "address_2", "city", "state", "zip_code"] + class PeopleForm(ModelForm): phone_number = PhoneNumberField(required=False) - + def clean(self): cleaned_data = super().clean() - if cleaned_data.get('phone_number'): - if len(cleaned_data.get('first_name')) == 0 or len(cleaned_data.get('last_name')) == 0 or len(cleaned_data.get('email')) == 0 or len(cleaned_data.get('phone_number').raw_input) == 0: - raise ValidationError ('A Field is missing') + if cleaned_data.get("phone_number"): + if ( + len(cleaned_data.get("first_name")) == 0 + or len(cleaned_data.get("last_name")) == 0 + or len(cleaned_data.get("email")) == 0 + or len(cleaned_data.get("phone_number").raw_input) == 0 + ): + raise ValidationError("A Field is missing") else: - raise ValidationError('No phone number provided') + raise ValidationError("No phone number provided") class Meta: model = MembershipPerson - fields = ["first_name","last_name","phone_number","email"] + fields = ["first_name", "last_name", "phone_number", "email"] + class CommitteeForm(ModelForm): - block_captain = forms.BooleanField(label="I can serve as a Block Captain (distribute newsletters & directories)", required=False) - coordinator = forms.BooleanField(label="I can serve as a Coordinator, SCHA Board Member Position (oversee & organize block captains)", required=False) + block_captain = forms.BooleanField( + label="I can serve as a Block Captain (distribute newsletters & directories)", + required=False, + ) + coordinator = forms.BooleanField( + label="I can serve as a Coordinator, SCHA Board Member Position (oversee & organize block captains)", + required=False, + ) egg_hunt = forms.BooleanField(label="Easter Egg Hunt (late March)", required=False) - spring_garage_sale = forms.BooleanField(label="Spring Garage Sale (May/June)", required=False) + spring_garage_sale = forms.BooleanField( + label="Spring Garage Sale (May/June)", required=False + ) golf_outing = forms.BooleanField(label="Golf Outing (Summer)", required=False) - ice_cream_social = forms.BooleanField(label="Ice Creame Social (August)", required=False) - fall_garage_sale = forms.BooleanField(label="Fall Garage Sale (September/October)", required=False) - halloween_party = forms.BooleanField(label="Halloween Party (October)", required=False) + ice_cream_social = forms.BooleanField( + label="Ice Creame Social (August)", required=False + ) + fall_garage_sale = forms.BooleanField( + label="Fall Garage Sale (September/October)", required=False + ) + halloween_party = forms.BooleanField( + label="Halloween Party (October)", required=False + ) santa_visit = forms.BooleanField(label="Santa Visits (December)", required=False) - website = forms.BooleanField(label="SCHA Newsletter/Website (wite articles, edit, report, etc)", required=False) - civic_affair = forms.BooleanField(label="Civic Affairs Journalist (report on school board/city council mtgs)", required=False) - phone_directory = forms.BooleanField(label="Annual Phone Directory (Help compile, edit, produce our Annual Neighborhood Directory)", required=False) - no_preference = forms.BooleanField(label="No Preference. I want to help in some way . Please email me.", required=False) + website = forms.BooleanField( + label="SCHA Newsletter/Website (wite articles, edit, report, etc)", + required=False, + ) + civic_affair = forms.BooleanField( + label="Civic Affairs Journalist (report on school board/city council mtgs)", + required=False, + ) + phone_directory = forms.BooleanField( + label="Annual Phone Directory (Help compile, edit, produce our Annual Neighborhood Directory)", + required=False, + ) + no_preference = forms.BooleanField( + label="No Preference. I want to help in some way . Please email me.", + required=False, + ) + class Meta: model = MembershipCommittee fields = [ @@ -76,6 +119,7 @@ class CommitteeForm(ModelForm): "no_preference", ] + class ServicesForm(ModelForm): babysitting = forms.BooleanField(label="Babysitting", required=False) lawn_mowing = forms.BooleanField(label="Lawn Mowing", required=False) @@ -84,6 +128,7 @@ class ServicesForm(ModelForm): petsitting = forms.BooleanField(label="Petsitting", required=False) house_sitting = forms.BooleanField(label="Housesitting", required=False) other = forms.BooleanField(label="Other", required=False) + class Meta: model = MembershipServices fields = [ @@ -95,7 +140,8 @@ class ServicesForm(ModelForm): "house_sitting", "other", "other_desc", - ] + ] + class PaymentImport(ModelForm): - pass \ No newline at end of file + pass diff --git a/schasite/migrations/0001_initial.py b/schasite/migrations/0001_initial.py index 3b7bfc1..5fe6814 100644 --- a/schasite/migrations/0001_initial.py +++ b/schasite/migrations/0001_initial.py @@ -9,91 +9,186 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='AddressModel', + name="AddressModel", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('address_1', models.CharField(max_length=128)), - ('address_2', models.CharField(blank=True, max_length=128)), - ('city', models.CharField(max_length=128)), - ('state', models.CharField(max_length=2)), - ('zip_code', models.CharField(max_length=5)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("address_1", models.CharField(max_length=128)), + ("address_2", models.CharField(blank=True, max_length=128)), + ("city", models.CharField(max_length=128)), + ("state", models.CharField(max_length=2)), + ("zip_code", models.CharField(max_length=5)), ], ), migrations.CreateModel( - name='Membership', + name="Membership", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('children', models.CharField(default='', max_length=256)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("children", models.CharField(default="", max_length=256)), ], ), migrations.CreateModel( - name='UsefulLinks', + name="UsefulLinks", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256)), - ('url', models.CharField(max_length=256)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=256)), + ("url", models.CharField(max_length=256)), ], ), migrations.CreateModel( - name='MembershipPerson', + name="MembershipPerson", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('first_name', models.CharField(blank=True, max_length=256, null=True)), - ('last_name', models.CharField(blank=True, max_length=256, null=True)), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, region=None, unique=True)), - ('email', models.EmailField(blank=True, max_length=254, null=True)), - ('membership', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='schasite.membership')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("first_name", models.CharField(blank=True, max_length=256, null=True)), + ("last_name", models.CharField(blank=True, max_length=256, null=True)), + ( + "phone_number", + phonenumber_field.modelfields.PhoneNumberField( + max_length=128, null=True, region=None, unique=True + ), + ), + ("email", models.EmailField(blank=True, max_length=254, null=True)), + ( + "membership", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="schasite.membership", + ), + ), ], ), migrations.CreateModel( - name='MembershipCommittee', + name="MembershipCommittee", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('block_captain', models.BooleanField(default=False)), - ('coordinator', models.BooleanField(default=False)), - ('egg_hunt', models.BooleanField(default=False)), - ('spring_garage_sale', models.BooleanField(default=False)), - ('golf_outing', models.BooleanField(default=False)), - ('ice_cream_social', models.BooleanField(default=False)), - ('fall_garage_sale', models.BooleanField(default=False)), - ('halloween_party', models.BooleanField(default=False)), - ('santa_visit', models.BooleanField(default=False)), - ('website', models.BooleanField(default=False)), - ('civic_affair', models.BooleanField(default=False)), - ('phone_directory', models.BooleanField(default=False)), - ('no_preference', models.BooleanField(default=False)), - ('membership', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.membership')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("block_captain", models.BooleanField(default=False)), + ("coordinator", models.BooleanField(default=False)), + ("egg_hunt", models.BooleanField(default=False)), + ("spring_garage_sale", models.BooleanField(default=False)), + ("golf_outing", models.BooleanField(default=False)), + ("ice_cream_social", models.BooleanField(default=False)), + ("fall_garage_sale", models.BooleanField(default=False)), + ("halloween_party", models.BooleanField(default=False)), + ("santa_visit", models.BooleanField(default=False)), + ("website", models.BooleanField(default=False)), + ("civic_affair", models.BooleanField(default=False)), + ("phone_directory", models.BooleanField(default=False)), + ("no_preference", models.BooleanField(default=False)), + ( + "membership", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="schasite.membership", + ), + ), ], ), migrations.CreateModel( - name='CalendarEvent', + name="CalendarEvent", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('event_name', models.CharField(max_length=256)), - ('start_date', models.DateField(blank=True, null=True)), - ('end_date', models.DateField(blank=True, null=True)), - ('location_name', models.CharField(blank=True, max_length=256, null=True)), - ('coordinator_email', models.EmailField(blank=True, max_length=256, null=True)), - ('event_link_name', models.CharField(blank=True, max_length=64, null=True)), - ('event_url', models.URLField(blank=True, max_length=256, null=True)), - ('location_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='schasite.addressmodel')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("event_name", models.CharField(max_length=256)), + ("start_date", models.DateField(blank=True, null=True)), + ("end_date", models.DateField(blank=True, null=True)), + ( + "location_name", + models.CharField(blank=True, max_length=256, null=True), + ), + ( + "coordinator_email", + models.EmailField(blank=True, max_length=256, null=True), + ), + ( + "event_link_name", + models.CharField(blank=True, max_length=64, null=True), + ), + ("event_url", models.URLField(blank=True, max_length=256, null=True)), + ( + "location_address", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="schasite.addressmodel", + ), + ), ], ), migrations.CreateModel( - name='AddressModel1', + name="AddressModel1", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('address_1', models.CharField(max_length=128)), - ('address_2', models.CharField(blank=True, max_length=128)), - ('city', models.CharField(max_length=128)), - ('state', models.CharField(max_length=2)), - ('zip_code', models.CharField(max_length=5)), - ('membership', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.membership')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("address_1", models.CharField(max_length=128)), + ("address_2", models.CharField(blank=True, max_length=128)), + ("city", models.CharField(max_length=128)), + ("state", models.CharField(max_length=2)), + ("zip_code", models.CharField(max_length=5)), + ( + "membership", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="schasite.membership", + ), + ), ], ), ] diff --git a/schasite/migrations/0002_alter_membership_children.py b/schasite/migrations/0002_alter_membership_children.py index 97547b0..ed73325 100644 --- a/schasite/migrations/0002_alter_membership_children.py +++ b/schasite/migrations/0002_alter_membership_children.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('schasite', '0001_initial'), + ("schasite", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='membership', - name='children', - field=models.CharField(blank=True, default='', max_length=256, null=True), + model_name="membership", + name="children", + field=models.CharField(blank=True, default="", max_length=256, null=True), ), ] diff --git a/schasite/migrations/0003_alter_membershipcommittee_block_captain_and_more.py b/schasite/migrations/0003_alter_membershipcommittee_block_captain_and_more.py index 9b2ff5f..eff36de 100644 --- a/schasite/migrations/0003_alter_membershipcommittee_block_captain_and_more.py +++ b/schasite/migrations/0003_alter_membershipcommittee_block_captain_and_more.py @@ -6,73 +6,73 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('schasite', '0002_alter_membership_children'), + ("schasite", "0002_alter_membership_children"), ] operations = [ migrations.AlterField( - model_name='membershipcommittee', - name='block_captain', + model_name="membershipcommittee", + name="block_captain", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='civic_affair', + model_name="membershipcommittee", + name="civic_affair", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='coordinator', + model_name="membershipcommittee", + name="coordinator", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='egg_hunt', + model_name="membershipcommittee", + name="egg_hunt", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='fall_garage_sale', + model_name="membershipcommittee", + name="fall_garage_sale", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='golf_outing', + model_name="membershipcommittee", + name="golf_outing", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='halloween_party', + model_name="membershipcommittee", + name="halloween_party", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='ice_cream_social', + model_name="membershipcommittee", + name="ice_cream_social", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='no_preference', + model_name="membershipcommittee", + name="no_preference", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='phone_directory', + model_name="membershipcommittee", + name="phone_directory", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='santa_visit', + model_name="membershipcommittee", + name="santa_visit", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='spring_garage_sale', + model_name="membershipcommittee", + name="spring_garage_sale", field=models.BooleanField(blank=True, default=False, null=True), ), migrations.AlterField( - model_name='membershipcommittee', - name='website', + model_name="membershipcommittee", + name="website", field=models.BooleanField(blank=True, default=False, null=True), ), ] diff --git a/schasite/migrations/0004_alter_membershipperson_phone_number.py b/schasite/migrations/0004_alter_membershipperson_phone_number.py index eee92f4..6a7bbe9 100644 --- a/schasite/migrations/0004_alter_membershipperson_phone_number.py +++ b/schasite/migrations/0004_alter_membershipperson_phone_number.py @@ -7,13 +7,15 @@ import phonenumber_field.modelfields class Migration(migrations.Migration): dependencies = [ - ('schasite', '0003_alter_membershipcommittee_block_captain_and_more'), + ("schasite", "0003_alter_membershipcommittee_block_captain_and_more"), ] operations = [ migrations.AlterField( - model_name='membershipperson', - name='phone_number', - field=phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, region=None), + model_name="membershipperson", + name="phone_number", + field=phonenumber_field.modelfields.PhoneNumberField( + max_length=128, null=True, region=None + ), ), ] diff --git a/schasite/migrations/0005_membershipservices.py b/schasite/migrations/0005_membershipservices.py index e9c4155..97bdd44 100644 --- a/schasite/migrations/0005_membershipservices.py +++ b/schasite/migrations/0005_membershipservices.py @@ -7,23 +7,58 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('schasite', '0004_alter_membershipperson_phone_number'), + ("schasite", "0004_alter_membershipperson_phone_number"), ] operations = [ migrations.CreateModel( - name='MembershipServices', + name="MembershipServices", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('babysitting', models.BooleanField(blank=True, default=False, null=True)), - ('lawn_mowing', models.BooleanField(blank=True, default=False, null=True)), - ('snow_shoveling', models.BooleanField(blank=True, default=False, null=True)), - ('leaf_raking', models.BooleanField(blank=True, default=False, null=True)), - ('petsitting', models.BooleanField(blank=True, default=False, null=True)), - ('house_sitting', models.BooleanField(blank=True, default=False, null=True)), - ('other', models.BooleanField(blank=True, default=False, null=True)), - ('other_desc', models.CharField(blank=True, default='', max_length=256, null=True)), - ('membership', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.membership')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "babysitting", + models.BooleanField(blank=True, default=False, null=True), + ), + ( + "lawn_mowing", + models.BooleanField(blank=True, default=False, null=True), + ), + ( + "snow_shoveling", + models.BooleanField(blank=True, default=False, null=True), + ), + ( + "leaf_raking", + models.BooleanField(blank=True, default=False, null=True), + ), + ( + "petsitting", + models.BooleanField(blank=True, default=False, null=True), + ), + ( + "house_sitting", + models.BooleanField(blank=True, default=False, null=True), + ), + ("other", models.BooleanField(blank=True, default=False, null=True)), + ( + "other_desc", + models.CharField(blank=True, default="", max_length=256, null=True), + ), + ( + "membership", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="schasite.membership", + ), + ), ], ), ] diff --git a/schasite/migrations/0006_calendareventaddressmodel_and_more.py b/schasite/migrations/0006_calendareventaddressmodel_and_more.py index fd91a7f..bd4c4c8 100644 --- a/schasite/migrations/0006_calendareventaddressmodel_and_more.py +++ b/schasite/migrations/0006_calendareventaddressmodel_and_more.py @@ -7,31 +7,41 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('schasite', '0005_membershipservices'), + ("schasite", "0005_membershipservices"), ] operations = [ migrations.CreateModel( - name='CalendarEventAddressModel', + name="CalendarEventAddressModel", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('address_1', models.CharField(max_length=128)), - ('address_2', models.CharField(blank=True, max_length=128)), - ('city', models.CharField(max_length=128)), - ('state', models.CharField(max_length=2)), - ('zip_code', models.CharField(max_length=5)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("address_1", models.CharField(max_length=128)), + ("address_2", models.CharField(blank=True, max_length=128)), + ("city", models.CharField(max_length=128)), + ("state", models.CharField(max_length=2)), + ("zip_code", models.CharField(max_length=5)), ], ), migrations.RemoveField( - model_name='calendarevent', - name='location_address', + model_name="calendarevent", + name="location_address", ), migrations.DeleteModel( - name='AddressModel', + name="AddressModel", ), migrations.AddField( - model_name='calendareventaddressmodel', - name='calendar_event', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.calendarevent'), + model_name="calendareventaddressmodel", + name="calendar_event", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, to="schasite.calendarevent" + ), ), ] diff --git a/schasite/migrations/0007_payments.py b/schasite/migrations/0007_payments.py index 1605a23..798efbc 100644 --- a/schasite/migrations/0007_payments.py +++ b/schasite/migrations/0007_payments.py @@ -8,18 +8,39 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('schasite', '0006_calendareventaddressmodel_and_more'), + ("schasite", "0006_calendareventaddressmodel_and_more"), ] operations = [ migrations.CreateModel( - name='Payments', + name="Payments", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date', models.DateField(default=datetime.datetime(2024, 3, 27, 17, 40, 28, 908036))), - ('status', models.CharField(default='Completed', max_length=256)), - ('email', models.EmailField(blank=True, max_length=254, null=True)), - ('person', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='schasite.membershipperson')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "date", + models.DateField( + default=datetime.datetime(2024, 3, 27, 17, 40, 28, 908036) + ), + ), + ("status", models.CharField(default="Completed", max_length=256)), + ("email", models.EmailField(blank=True, max_length=254, null=True)), + ( + "person", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="schasite.membershipperson", + ), + ), ], ), ] diff --git a/schasite/migrations/0008_alter_payments_date.py b/schasite/migrations/0008_alter_payments_date.py index 0823b19..ad8480e 100644 --- a/schasite/migrations/0008_alter_payments_date.py +++ b/schasite/migrations/0008_alter_payments_date.py @@ -7,13 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('schasite', '0007_payments'), + ("schasite", "0007_payments"), ] operations = [ migrations.AlterField( - model_name='payments', - name='date', - field=models.DateField(default=datetime.datetime(2024, 3, 27, 17, 41, 22, 742260, tzinfo=datetime.timezone.utc)), + model_name="payments", + name="date", + field=models.DateField( + default=datetime.datetime( + 2024, 3, 27, 17, 41, 22, 742260, tzinfo=datetime.timezone.utc + ) + ), ), ] diff --git a/schasite/migrations/0009_schaofficer_alter_payments_date.py b/schasite/migrations/0009_schaofficer_alter_payments_date.py new file mode 100644 index 0000000..20f949e --- /dev/null +++ b/schasite/migrations/0009_schaofficer_alter_payments_date.py @@ -0,0 +1,40 @@ +# Generated by Django 5.2 on 2025-04-14 15:33 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("schasite", "0008_alter_payments_date"), + ] + + operations = [ + migrations.CreateModel( + name="SCHAOfficer", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ("position", models.CharField(max_length=255)), + ("email", models.EmailField(max_length=255)), + ], + ), + migrations.AlterField( + model_name="payments", + name="date", + field=models.DateField( + default=datetime.datetime( + 2025, 4, 14, 15, 33, 4, 942154, tzinfo=datetime.timezone.utc + ) + ), + ), + ] diff --git a/schasite/models.py b/schasite/models.py index f57e5e7..4c97305 100644 --- a/schasite/models.py +++ b/schasite/models.py @@ -3,7 +3,7 @@ from phonenumber_field.modelfields import PhoneNumberField import datetime from django.utils import timezone - + # Create your models here. class UsefulLinks(models.Model): name = models.CharField(max_length=256) @@ -22,7 +22,10 @@ class Membership(models.Model): return self.addressmodel1.address_1 def get_person_1(self): - emails = [item.email for item in MembershipPerson.objects.filter(membership_id=self.id)] + emails = [ + item.email + for item in MembershipPerson.objects.filter(membership_id=self.id) + ] # remove all the Nones filtered_emails = [i for i in emails if i is not None] if len(filtered_emails) == 0: @@ -33,14 +36,14 @@ class Membership(models.Model): def __str__(self): return self.get_address_str() + " | " + self.get_person_1() + class AddressModel1(models.Model): membership = models.OneToOneField(Membership, on_delete=models.CASCADE) address_1 = models.CharField(max_length=128) address_2 = models.CharField(max_length=128, blank=True) city = models.CharField(max_length=128) state = models.CharField(max_length=2) - zip_code = models.CharField(max_length=5) - + zip_code = models.CharField(max_length=5) class CalendarEvent(models.Model): @@ -51,38 +54,45 @@ class CalendarEvent(models.Model): coordinator_email = models.EmailField(max_length=256, blank=True, null=True) event_link_name = models.CharField(max_length=64, blank=True, null=True) event_url = models.URLField(max_length=256, blank=True, null=True) + description= models.CharField(max_length=1024, default="") def has_date(self): return not self.start_date is None - + def past_event(self): if self.has_date(): return self.start_date <= datetime.datetime.now().date() else: return False - + def future_event(self): if self.has_date(): return self.start_date > datetime.datetime.now().date() else: return False - + def no_date(self): return not self.has_date() + class CalendarEventAddressModel(models.Model): calendar_event = models.OneToOneField(CalendarEvent, on_delete=models.CASCADE) address_1 = models.CharField(max_length=128) address_2 = models.CharField(max_length=128, blank=True) city = models.CharField(max_length=128) state = models.CharField(max_length=2) - zip_code = models.CharField(max_length=5) + zip_code = models.CharField(max_length=5) + + def __str__(self): + return ( + self.address_1 + ", " + self.city + ", " + self.state + " " + self.zip_code + ) + - def __str__ (self): - return self.address_1 + ", " + self.city + ", " + self.state + " " + self.zip_code - class MembershipPerson(models.Model): - membership = models.ForeignKey(Membership, on_delete=models.CASCADE, blank=True, null=True) + membership = models.ForeignKey( + Membership, on_delete=models.CASCADE, blank=True, null=True + ) first_name = models.CharField(max_length=256, blank=True, null=True) last_name = models.CharField(max_length=256, blank=True, null=True) phone_number = PhoneNumberField(blank=False, null=True) @@ -92,8 +102,6 @@ class MembershipPerson(models.Model): return self.email if self.email else "No email" - - class MembershipCommittee(models.Model): membership = models.OneToOneField(Membership, on_delete=models.CASCADE) block_captain = models.BooleanField(default=False, blank=True, null=True) @@ -110,6 +118,7 @@ class MembershipCommittee(models.Model): phone_directory = models.BooleanField(default=False, blank=True, null=True) no_preference = models.BooleanField(default=False, blank=True, null=True) + class MembershipServices(models.Model): membership = models.OneToOneField(Membership, on_delete=models.CASCADE) babysitting = models.BooleanField(default=False, blank=True, null=True) @@ -121,8 +130,36 @@ class MembershipServices(models.Model): other = models.BooleanField(default=False, blank=True, null=True) other_desc = models.CharField(default="", blank=True, null=True, max_length=256) + class Payments(models.Model): date = models.DateField(default=timezone.now()) - status = models.CharField(default='Completed', max_length=256) + status = models.CharField(default="Completed", max_length=256) email = models.EmailField(blank=True, null=True) - person = models.ForeignKey(MembershipPerson, on_delete=models.CASCADE, blank=True,null=True) \ No newline at end of file + person = models.ForeignKey( + MembershipPerson, on_delete=models.CASCADE, blank=True, null=True + ) + + +class SCHAOfficer(models.Model): + name = models.CharField(max_length=255) + position = models.CharField(max_length=255) + email = models.EmailField(max_length=255) + +# class CommunitySchools(models.Model): +# name = models.CharField(max_length=255) +# name_school_url = models.URLField(max_length=256) +# rating_url = models.URLField(max_length=256) +# rating = models.DecimalField(max_digits=5, decimal_places=2) +# distance = models.DecimalField(max_digits=3, decimal_places=1) +# principal = models.CharField(max_length=255) +# grades = models.CharField(max_length=255) + +# class CommunityShoppingAndDining(models.Model): +# name = models.CharField(max_length=255) +# distance = models.DecimalField(max_digits=3, decimal_places=1) +# description = models.CharField(max_length=1024) + +# class CommunityParks(models.Model): +# name = models.CharField(max_length=255) +# distance = models.DecimalField(max_digits=3, decimal_places=1) +# description = models.CharField(max_length=1024) \ No newline at end of file diff --git a/schasite/static/css/style2.css b/schasite/static/css/style2.css new file mode 100644 index 0000000..0f033df --- /dev/null +++ b/schasite/static/css/style2.css @@ -0,0 +1,47 @@ +/* Custom Styles */ +:root { + --bs-success-rgb: 40, 167, 69; +} + +body { + padding-top: 56px; +} + +section { + scroll-margin-top: 70px; +} + +/* Hero Section */ +#home { + background-color: rgba(var(--bs-success-rgb), 0.1); +} + +/* News and Contact Sections */ +.bg-success-10 { + background-color: rgba(var(--bs-success-rgb), 0.1); +} + +/* Card hover effect */ +.card { + transition: transform 0.2s ease-in-out; +} + +.card:hover { + transform: translateY(-5px); +} + +/* Contact icons */ +.bi { + vertical-align: -.125em; +} + +/* Form validation */ +.was-validated .form-control:invalid, +.form-control.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-control:valid, +.form-control.is-valid { + border-color: #198754; +} \ No newline at end of file diff --git a/schasite/templates/schasite/about_us2.html b/schasite/templates/schasite/about_us2.html new file mode 100644 index 0000000..3f3d172 --- /dev/null +++ b/schasite/templates/schasite/about_us2.html @@ -0,0 +1,276 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association +{% endblock %} + +{% block content %} + +
+
+
+
+ Local Schools +
+
+

Excellent Schools Serving Our Community

+

Stonehedge Community Homeowners Association is proud to be served by some of the highest-rated schools in the district, providing quality education for all ages.

+ +
+
+

+ +

+
+
+

Rating: 87.5/100 (U.S. News)
+ Grades: K-5
+ Enrollment: 414
+ Distance: 2.3 miles from community entrance
+ Principal: Robert Cerny

+ Visit Website +
+
+
+
+

+ +

+
+
+

Rating: 75.69/10 (U.S. News)
+ Grades: 6-8
+ Enrollment: 674
+ Distance: 2.5 miles from community entrance
+ Principal: Rachel Bednar

+ Visit Website +
+
+
+
+

+ +

+
+
+

Rating: 90.43/10 (U.S. News)
+ Grades: 9-12
+ Enrollment: 1845
+ Distance: 3.1 miles from community entrance
+ Principal: Lorie Campos

+ Visit Website +
+
+
+
+

+ +

+
+
+ Grades: Pre-K-8
+ Distance: 2.5 miles from community entrance
+ Principal: Adam Furgson

+ Visit Website +
+
+
+
+

+ +

+
+
+ Grades: 9-12
+ Enrollment: 698
+ Distance: 2.7 miles from community entrance
+ Principal: TBD

+ Visit Website +
+
+
+
+

+ +

+
+
+ Grades: 9-12
+ Enrollment: 1265
+ Distance: 5.9 miles from community entrance
+ Principal: TBD

+ Visit Website +
+
+
+
+
+
+
+
+ + +
+
+
+
+ Community History +
+
+

Our Rich History

+ +
+
+
+
+
+

1977

+
+
+

Levitt Homes began building the Stonehedge Subdivision.  In 1978, Levitt had financial problems and construction was halted for many months until local builders Joe Keim, Ed Keim and Faganel Builders took over the development of the Stonehedge subdivision in South Wheaton. Today these attractive residences are much in demand. The Orchard Cove subdivision was established in 1985 and development began in the Marywood subdivision in 1994.  Both Orchard Cove & Marywood were built by Keim. 

+

hese subdivisions offer a variety of spacious, two-story Georgian, Tudor, Victorian and salt box style homes, mixed with a limited number of contemporaries, split levels and ranches.

+
+
+
+ +
+
+
+
+
+ + +
+
+

Local Shopping & Dining

+

Stonehedge Community Homeowners Association is conveniently located near excellent shopping and dining options to meet all your needs.

+ +
+
+
+ Greenwood Mall +
+
Danada
+

1.0 miles from community

+

Over 10 stores including major department stores, fashion retailers, and specialty shops.

+
+ +
+
+
+
+ Farmers Market +
+
Downtown Wheaton
+

2.7 miles from community

+

Fresh local produce, artisanal foods, and handmade goods every Saturday morning.

+
+ +
+
+ +
+
+ Farmers Market +
+
Wheaton Farmersmarket
+

2.8 miles from community

+

Fresh local produce, artisanal foods, and handmade goods every Saturday morning.

+
+ +
+
+
+
+ Dining District +
+
Downtown Naperville
+

6.2 miles from community

+

Diverse restaurants featuring Italian, Asian, Mexican, and American cuisine options.

+
+ +
+
+
+ +
+
+ + +
+
+

Parks

+ +
+
+
+
+
+ Community Park +
+
+
+
Brighton Park
+

Within SCHA

+
    +
  • Playground
  • +
  • Picninc Tables
  • +
  • Dogs Allowed
  • +
+

Open daily from dawn to dusk

+
+
+
+
+
+ +
+
+
+
+ Nature Preserve +
+
+
+
Seven Gables Park
+

0.5 miles from SCHA

+

66.5 acres featuring sports fields, tennis courts & an ice rink, plus other recreational facilities.

+
    +
  • Playground
  • +
  • Baseball Field
  • +
  • Tennis Court
  • +
  • BasketballCourt
  • +
  • Picninc Tables
  • +
  • Dogs Allowed
  • +
+

Open daily from 8am to sunset

+
+
+
+
+
+
+
+
+{% endblock %} diff --git a/schasite/templates/schasite/base2.html b/schasite/templates/schasite/base2.html new file mode 100644 index 0000000..7dbe5c8 --- /dev/null +++ b/schasite/templates/schasite/base2.html @@ -0,0 +1,90 @@ + +{% load static %} + + + + + {% block pagetitle %} + {% endblock %} + + + + + + + + + + + {% block content %} + {% endblock %} + + + + + + + + + {% block extra_js %} + {% endblock %} + + \ No newline at end of file diff --git a/schasite/templates/schasite/calendar2.html b/schasite/templates/schasite/calendar2.html new file mode 100644 index 0000000..72664de --- /dev/null +++ b/schasite/templates/schasite/calendar2.html @@ -0,0 +1,202 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association + + +{% endblock %} + +{% block content %} +
+
+ +
+
+ +
+
+ + +
+ +
+
+ {% for event in future_events %} +
+
+
+
+

{{ event.event_name }}

+ Upcoming +
+
+
+
+
+ Community Picnic +
+
+
+

Date: {{ event.start_date }}

+

Time: 11:00 AM - 3:00 PM

+

Location: {{ event.location_name }}

+

Address:

+

Coordinator: {{ event.coordinator_name }}

+

Email: {{ event.coordinator_email }}

+
+

{{ event.description }}

+
+ {{ event.event_link_name }} + {% if event.rsvp_date %} + RSVP by {{ event.rsvp_date }} + {% endif %} +
+
+
+
+
+
+ + {% endfor %} +
+
+ + +
+
+ + {% for event in future_events %} +
+
+
+
+

{{ event.event_name }}

+ Completed +
+
+
+
+
+ Spring Cleanup +
+
+
+

Date: {{ event.start_date }}

+

Time: 9:00 AM - 12:00 PM

+

Location: {{ event.location_name }}

+

Address:

+

Coordinator: {{ event.coordinator_name }}

+

Email: {{ event.coordinator_email }}

+
+

{{ event.description }}

+
+ Event Recap + 52 volunteers participated +
+
+
+
+
+
+ {% endfor %} + + +
+
+
+
+
+{% endblock %} +{% block extra_js %} + + + +{% endblock %} \ No newline at end of file diff --git a/schasite/templates/schasite/dues2.html b/schasite/templates/schasite/dues2.html new file mode 100644 index 0000000..bbf4c6e --- /dev/null +++ b/schasite/templates/schasite/dues2.html @@ -0,0 +1,230 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association + +{% endblock %} + +{% block content %} +
+
+
+
+ +
+
+

Payment Information

+
+
+
+ + You will be redirected to our secure payment processor (Stripe) to complete your transaction. +
+ +

Annual Dues

+ +
+ + + + + + + + + + + + + +
Payment OptionAmount
Full Payment (Annual)$30.00
+
+ + +
+
+ + +
+
+

Payment Options

+
+
+
+ +
+
+
+ +

Credit/Debit Card

+

Pay securely with Visa, Mastercard, American Express, or Discover.

+ + Pay with Card + +
+
+
+
+ +
+ + +
+
+
Other Payment Methods
+ +
+
+
+
+ + +
+
+

Payment FAQ

+
+
+
+
+

+ +

+
+
+ No, the HOA absorbs all processing fees for online payments. You pay exactly your dues amount with no additional fees. +
+
+
+
+

+ +

+
+
+ Credit/debit card payments are posted immediately. +
+
+
+
+

+ +

+
+
+ Online we accept all major credit/debit cards (Visa, Mastercard, American Express, Discover). For in-person or mail payments, we accept checks or money orders made payable to "SCHA" +
+
+
+
+
+
+
+
+
+
+ +{% endblock %} +{% block extra_js %} + + + + + +{% endblock %} \ No newline at end of file diff --git a/schasite/templates/schasite/index2.html b/schasite/templates/schasite/index2.html new file mode 100644 index 0000000..6e8c7e0 --- /dev/null +++ b/schasite/templates/schasite/index2.html @@ -0,0 +1,208 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association +{% endblock %} + +{% block content %} + +
+
+
+
+

Welcome to Stonehedge Community Homeowners Association

+

A premier community dedicated to maintaining beautiful homes, safe neighborhoods, and a high quality of life for all residents.

+ Learn More +
+
+ Stonehedge Community Homeowners Association +
+
+
+
+ + +
+
+

About Our Community

+
+
+
+ Community Amenities +
+
Amenities
+

Our community features a swimming pool, playground, walking trails, and clubhouse available for resident use.

+
+
+
+
+
+ HOA Board +
+
HOA Board
+

Meet our elected board members who volunteer their time to maintain and improve our neighborhood.

+
+
+
+
+
+ Community Rules +
+
Community Rules
+

Learn about our community guidelines designed to maintain property values and quality of life for all residents.

+
+
+
+
+
+
+ + +
+
+

Community News & Events

+
+
+
+
+
Annual Community Picnic
+

Join us on June 15th for our annual community picnic at the clubhouse. Food, games, and fun for the whole family!

+
+ +
+
+
+
+
+
Landscaping Updates
+

New landscaping will be installed in common areas beginning next month. Expect temporary parking restrictions.

+
+ +
+
+
+ +
+
+ + +
+
+

Community Documents

+
+
+
+
+
Governing Documents
+
+ +
+
+
+
+
+
Meeting Minutes
+
+ +
+
+ +
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/schasite/templates/schasite/membership_form2.html b/schasite/templates/schasite/membership_form2.html new file mode 100644 index 0000000..f168960 --- /dev/null +++ b/schasite/templates/schasite/membership_form2.html @@ -0,0 +1,414 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
+

New Member Information

+
+
+
+ +
+ Household Information + + +
+
+ + +
+ Please provide your street address. +
+
+
+ + +
+
+ + +
+ Please provide your city. +
+
+
+ + +
+ Please select your state. +
+
+
+ + +
+ Please provide your ZIP code. +
+
+
+ + +
+
+
Primary Member*
+
+
+ + +
+ Please provide first name. +
+
+
+ + +
+ Please provide last name. +
+
+
+ + +
+ Please provide a valid email. +
+
+
+ + +
+ Please provide phone number. +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+ + +
+ Committee Interests +

Check all committees you're interested in joining:

+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+
+ + +
+ Services +

Check if you're interested in providing these services to neighbors:

+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+
+ + +
+ You must agree before submitting. +
+
+
+ +
+ + +
+
+
+
+
+
+
+
+ + + + +{% endblock %} + + +{% block extra_js %} + +{% endblock %} \ No newline at end of file diff --git a/schasite/templates/schasite/newsletters2.html b/schasite/templates/schasite/newsletters2.html new file mode 100644 index 0000000..69dc2ad --- /dev/null +++ b/schasite/templates/schasite/newsletters2.html @@ -0,0 +1,9 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association +{% endblock %} + +{% block content %} +{% endblock %} \ No newline at end of file diff --git a/schasite/templates/schasite/scha_board2.html b/schasite/templates/schasite/scha_board2.html new file mode 100644 index 0000000..ebc371a --- /dev/null +++ b/schasite/templates/schasite/scha_board2.html @@ -0,0 +1,149 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association + +{% endblock %} + +{% block content %} +
+
+ +
+
+
+
+

2025-2026 Stonehedge Community Homeowners Association Board

+

The Stonehedge Community Homeowners Association is governed by a volunteer board of directors elected by the community members. Board members serve two-year terms and are responsible for overseeing the community's operations, finances, and enforcement of covenants.

+

Board meetings are held monthly and are open to all residents. View meeting schedule.

+
+
+
+
+ + + + +
+ {% for officer in officers %} + {% if officer %} +
+
+
+

{{ officer.position }}

+
+
+ John Smith +
{{ officer.name }}
+ + +
+
+
+ {% else %} +
+
+
+

TBD

+
+
+ John Smith +
TBD
+

TBD

+

TBD

+
+
+
+ {% endif %} + + {% endfor %} + + + +
+
+
+
+

HOA Committees

+
+
+
+
+
+
+
Architectural Review
+

Reviews all exterior modification requests to ensure compliance with community standards.

+

Chair: Robert Wilson

+ Contact Committee +
+
+
+
+
+
+
Social & Events
+

Plans community events, holiday celebrations, and social gatherings.

+

Chair: Lisa Martinez

+ Contact Committee +
+
+
+
+
+
+
Landscape & Maintenance
+

Oversees common area maintenance and landscaping improvements.

+

Chair: David Thompson

+ Contact Committee +
+
+
+
+ +
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/schasite/templates/schasite/useful_links2.html b/schasite/templates/schasite/useful_links2.html new file mode 100644 index 0000000..e4b0951 --- /dev/null +++ b/schasite/templates/schasite/useful_links2.html @@ -0,0 +1,290 @@ +{% extends 'schasite/base2.html' %} +{% load static %} + +{% block pagetitle %} +Stonehedge Community Homeowners Association + +{% endblock %} + +{% block content %} +
+
+
+
+
+
+

Useful Links

+
+
+
+ + + + + + + + + {% for link in links %} + + + + + {% endfor %} + +
ResourceLink
{{ link.name }}Visit Site
+
+
+
+ + + + + + + + + + + +
+
+
+
+ +{% endblock %} + + +{% block extra_js %} + + + + +{% endblock %} \ No newline at end of file diff --git a/schasite/urls.py b/schasite/urls.py index 8533882..62df619 100644 --- a/schasite/urls.py +++ b/schasite/urls.py @@ -11,7 +11,16 @@ urlpatterns = [ path("dues", views.dues, name="dues"), path("membership_form", views.membership_form, name="membership_form"), path("scha_board", views.scha_board, name="scha_board"), + # updated UI urls + path("index2", views.index2, name="index2"), + path("about_us2", views.about_us2, name="about_us2"), + path("calendar2", views.calendar2, name="calendar2"), + path("newsletters2", views.newsletters2, name="newsletters2"), + path("dues2", views.dues2, name="dues2"), + path("membership_form2", views.membership_form2, name="membership_form2"), + path("scha_board2", views.scha_board2, name="scha_board2"), + path("useful_links2", views.useful_links2, name="useful_links2"), # stripe specific urls below - path('config/', views.stripe_config), - path('create-checkout-session/', views.create_checkout_session), -] \ No newline at end of file + path("config/", views.stripe_config), + path("create-checkout-session/", views.create_checkout_session), +] diff --git a/schasite/views.py b/schasite/views.py index 84e5cf5..a5dd144 100644 --- a/schasite/views.py +++ b/schasite/views.py @@ -1,66 +1,80 @@ from django.shortcuts import render, redirect -from .models import UsefulLinks, CalendarEvent, MembershipPerson, Payments -from .forms import ChildrenForm, AddressForm, PeopleForm, CommitteeForm, ServicesForm#, CaptchaForm +from .models import UsefulLinks, CalendarEvent, MembershipPerson, Payments, SCHAOfficer +from .forms import ( + ChildrenForm, + AddressForm, + PeopleForm, + CommitteeForm, + ServicesForm, +) # , CaptchaForm from django.db import transaction, IntegrityError + # Stripe required imports -from django.conf import settings # new +from django.conf import settings # new from django.http.response import JsonResponse, HttpResponse -from django.views.decorators.csrf import csrf_exempt # new -import stripe +from django.views.decorators.csrf import csrf_exempt # new +import stripe """ Strip Stuff Tutorial: https://testdriven.io/blog/django-stripe-tutorial/ """ + + def dues(request): return render(request, "schasite/dues.html", {}) + @csrf_exempt def stripe_config(request): - if request.method == 'GET': - stripe_config = {'publicKey': settings.STRIPE_PUBLISHABLE_KEY} + if request.method == "GET": + stripe_config = {"publicKey": settings.STRIPE_PUBLISHABLE_KEY} return JsonResponse(stripe_config, safe=False) + @csrf_exempt def create_checkout_session(request): - if request.method == 'GET': + if request.method == "GET": domain_url = "http://localhost:8000/" stripe.api_key = settings.STRIPE_SECRET_KEY try: checkout_session = stripe.checkout.Session.create( - success_url = domain_url+'success?session_id={CHECKOUT_SESSION_ID}', - cancel_url = domain_url+'cancelled/', - payment_method_types=['card'], + success_url=domain_url + "success?session_id={CHECKOUT_SESSION_ID}", + cancel_url=domain_url + "cancelled/", + payment_method_types=["card"], mode="payment", - line_items = [{ - # 'name':'SCHA Dues', - 'quantity': 1, - # 'currency': 'usd', - 'price': 'price_1OxZLfDV0RPXOyxG5ipjhUXk', - }] + line_items=[ + { + # 'name':'SCHA Dues', + "quantity": 1, + # 'currency': 'usd', + "price": "price_1OxZLfDV0RPXOyxG5ipjhUXk", + } + ], ) - return JsonResponse({'sessionId': checkout_session['id']}) + return JsonResponse({"sessionId": checkout_session["id"]}) except Exception as e: - return JsonResponse({'error': str(e)}) + return JsonResponse({"error": str(e)}) + def stripe_success(request): return render(request, "schasite/dues_success.html", {}) + def stripe_cancelled(request): return render(request, "schasite/dues_cancelled.html", {}) + @csrf_exempt def stripe_webhook(request): stripe.api_key = settings.STRIPE_SECRET_KEY endpoint_secret = settings.STRIPE_ENDPOINT_SECRET payload = request.body - sig_header = request.META['HTTP_STRIPE_SIGNATURE'] + sig_header = request.META["HTTP_STRIPE_SIGNATURE"] event = None try: - event = stripe.Webhook.construct_event( - payload, sig_header, endpoint_secret - ) + event = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret) except ValueError as e: # Invalid payload return HttpResponse(status=400) @@ -69,78 +83,136 @@ def stripe_webhook(request): return HttpResponse(status=400) # Handle the checkout.session.completed event - if event['type'] == 'checkout.session.completed': + if event["type"] == "checkout.session.completed": email = None try: - email = event['data']['object']['customer_details']['email'] + email = event["data"]["object"]["customer_details"]["email"] except: pass - person = MembershipPerson.objects.filter(email=email).first() # just take the first + person = MembershipPerson.objects.filter( + email=email + ).first() # just take the first - payment = Payments.objects.create( - email=email, - person = person - ) + payment = Payments.objects.create(email=email, person=person) # try to link to a member payment.save() # TODO: run some custom code here return HttpResponse(status=200) + """ Django Stuff """ -def useful_links(request): + + +def useful_links(request): useful_links = UsefulLinks.objects.all() return render(request, "schasite/useful_links.html", {"links": useful_links}) -def index(request): - return render(request, "schasite/index.html", {}) -def about_us(request): - return render(request, "schasite/about_us.html", {}) +def index2(request): + return render(request, "schasite/index2.html", {}) -def calendar(request): + +def about_us2(request): + return render(request, "schasite/about_us2.html", {}) + + +def newsletters2(request): + return render(request, "schasite/newsletters2.html", {}) + + +def calendar2(request): all_events = CalendarEvent.objects.all() future_events = [event if event.future_event() else None for event in all_events] past_events = [event if event.past_event() else None for event in all_events] # remove none for each list sanitized_future_events = [i for i in future_events if i is not None] sanitized_past_events = [i for i in past_events if i is not None] - return render(request, "schasite/calendar.html", {'future_events': sanitized_future_events, - 'past_events': sanitized_past_events}) + return render( + request, + "schasite/calendar2.html", + { + "future_events": sanitized_future_events, + "past_events": sanitized_past_events, + }, + ) -def newsletters(request): - return render(request, "schasite/newsletters.html", {}) -def membership_form(request): +def scha_board2(request): + def get_officer(position_name): + try: + return SCHAOfficer.objects.get(position=position_name) + except: + return None + + officers = [ + get_officer("President"), + get_officer("1st Vice President"), + get_officer("2nd Vice President"), + get_officer("Treasurer"), + get_officer("Secretary"), + get_officer("Website"), + get_officer("Membership"), + get_officer("Directory"), + get_officer("Facebook"), + get_officer("Eblasts"), + ] + + return render(request, "schasite/scha_board2.html", {"officers": officers}) + + +def dues2(request): + return render(request, "schasite/dues2.html", {}) + + +def membership_form2(request): def sanitize_phone_number(data): if len(data) > 0: - data = data.replace('-','') - if not data.startswith('+1'): - data = '+1' + data - + data = data.replace("-", "") + if not data.startswith("+1"): + data = "+1" + data + return data + if request.method == "POST": # before we pass in the data we want to sanitize the phone numbers post_data = request.POST.copy() - post_data.update({'person1-phone_number':sanitize_phone_number(post_data['person1-phone_number'])}) - post_data.update({'person2-phone_number':sanitize_phone_number(post_data['person2-phone_number'])}) + post_data.update( + { + "person1-phone_number": sanitize_phone_number( + post_data["person1-phone_number"] + ) + } + ) + post_data.update( + { + "person2-phone_number": sanitize_phone_number( + post_data["person2-phone_number"] + ) + } + ) membershipForm = ChildrenForm(post_data) addressForm = AddressForm(post_data) - peopleForm1 = PeopleForm(post_data, prefix='person1') - peopleForm2 = PeopleForm(post_data, prefix='person2') + peopleForm1 = PeopleForm(post_data, prefix="person1") + peopleForm2 = PeopleForm(post_data, prefix="person2") servicesForm = ServicesForm(post_data) - committeeForm= CommitteeForm(post_data) + committeeForm = CommitteeForm(post_data) # captchaForm = CaptchaForm(post_data) - - - if membershipForm.is_valid() and addressForm.is_valid() and committeeForm.is_valid() and (peopleForm1.is_valid() or peopleForm2.is_valid()) and servicesForm.is_valid(): # and captchaForm.is_valid(): + + if ( + membershipForm.is_valid() + and addressForm.is_valid() + and committeeForm.is_valid() + and (peopleForm1.is_valid() or peopleForm2.is_valid()) + and servicesForm.is_valid() + ): # and captchaForm.is_valid(): with transaction.atomic(): membershipForm = ChildrenForm({**post_data}) membership = membershipForm.save(commit=False) membership.save() - + if peopleForm1.is_valid(): people1_obj = peopleForm1.save(commit=False) people1_obj.membership = membership @@ -163,37 +235,183 @@ def membership_form(request): address_obj.membership = membership address_obj.save() - return redirect('index') + return redirect("index") - else: - return render(request, - "schasite/membership_form.html", - { - 'membershipForm': ChildrenForm, - 'peopleForm1': peopleForm1, - 'peopleForm2': peopleForm2, - 'addressForm': addressForm, - 'committeeForm' : committeeForm, - 'servicesForm': servicesForm, - # 'captchaForm': captchaForm, - } ) + return render( + request, + "schasite/membership_form2.html", + { + "membershipForm": ChildrenForm, + "peopleForm1": peopleForm1, + "peopleForm2": peopleForm2, + "addressForm": addressForm, + "committeeForm": committeeForm, + "servicesForm": servicesForm, + # 'captchaForm': captchaForm, + }, + ) else: - return render(request, - "schasite/membership_form.html", - {'membershipForm': ChildrenForm(), - 'peopleForm1': PeopleForm(prefix='person1'), - 'peopleForm2': PeopleForm(prefix='person2'), - 'committeeForm' : CommitteeForm(), - 'servicesForm': ServicesForm(), - # 'captchaForm': CaptchaForm(), - "addressForm": AddressForm( - initial={ - "city": "Wheaton", - "state": "IL", - "zip_code": 60189, - } - )}) + return render( + request, + "schasite/membership_form2.html", + { + "membershipForm": ChildrenForm(), + "peopleForm1": PeopleForm(prefix="person1"), + "peopleForm2": PeopleForm(prefix="person2"), + "committeeForm": CommitteeForm(), + "servicesForm": ServicesForm(), + # 'captchaForm': CaptchaForm(), + "addressForm": AddressForm( + initial={ + "city": "Wheaton", + "state": "IL", + "zip_code": 60189, + } + ), + }, + ) + + +def useful_links2(request): + useful_links = UsefulLinks.objects.all() + return render(request, "schasite/useful_links2.html", {"links": useful_links}) + + +def index(request): + return render(request, "schasite/index.html", {}) + + +def about_us(request): + return render(request, "schasite/about_us.html", {}) + + +def calendar(request): + all_events = CalendarEvent.objects.all() + future_events = [event if event.future_event() else None for event in all_events] + past_events = [event if event.past_event() else None for event in all_events] + # remove none for each list + sanitized_future_events = [i for i in future_events if i is not None] + sanitized_past_events = [i for i in past_events if i is not None] + return render( + request, + "schasite/calendar.html", + { + "future_events": sanitized_future_events, + "past_events": sanitized_past_events, + }, + ) + + +def newsletters(request): + return render(request, "schasite/newsletters.html", {}) + + +def membership_form(request): + def sanitize_phone_number(data): + if len(data) > 0: + data = data.replace("-", "") + if not data.startswith("+1"): + data = "+1" + data + + return data + + if request.method == "POST": + # before we pass in the data we want to sanitize the phone numbers + post_data = request.POST.copy() + post_data.update( + { + "person1-phone_number": sanitize_phone_number( + post_data["person1-phone_number"] + ) + } + ) + post_data.update( + { + "person2-phone_number": sanitize_phone_number( + post_data["person2-phone_number"] + ) + } + ) + membershipForm = ChildrenForm(post_data) + addressForm = AddressForm(post_data) + peopleForm1 = PeopleForm(post_data, prefix="person1") + peopleForm2 = PeopleForm(post_data, prefix="person2") + servicesForm = ServicesForm(post_data) + committeeForm = CommitteeForm(post_data) + # captchaForm = CaptchaForm(post_data) + + if ( + membershipForm.is_valid() + and addressForm.is_valid() + and committeeForm.is_valid() + and (peopleForm1.is_valid() or peopleForm2.is_valid()) + and servicesForm.is_valid() + ): # and captchaForm.is_valid(): + with transaction.atomic(): + membershipForm = ChildrenForm({**post_data}) + membership = membershipForm.save(commit=False) + membership.save() + + if peopleForm1.is_valid(): + people1_obj = peopleForm1.save(commit=False) + people1_obj.membership = membership + people1_obj.save() + + if peopleForm2.is_valid(): + people2_obj = peopleForm2.save(commit=False) + people2_obj.membership = membership + people2_obj.save() + + committee_obj = committeeForm.save(commit=False) + committee_obj.membership = membership + committee_obj.save() + + services_obj = servicesForm.save(commit=False) + services_obj.membership = membership + services_obj.save() + + address_obj = addressForm.save(commit=False) + address_obj.membership = membership + address_obj.save() + + return redirect("index") + + else: + return render( + request, + "schasite/membership_form.html", + { + "membershipForm": ChildrenForm, + "peopleForm1": peopleForm1, + "peopleForm2": peopleForm2, + "addressForm": addressForm, + "committeeForm": committeeForm, + "servicesForm": servicesForm, + # 'captchaForm': captchaForm, + }, + ) + else: + return render( + request, + "schasite/membership_form.html", + { + "membershipForm": ChildrenForm(), + "peopleForm1": PeopleForm(prefix="person1"), + "peopleForm2": PeopleForm(prefix="person2"), + "committeeForm": CommitteeForm(), + "servicesForm": ServicesForm(), + # 'captchaForm': CaptchaForm(), + "addressForm": AddressForm( + initial={ + "city": "Wheaton", + "state": "IL", + "zip_code": 60189, + } + ), + }, + ) + def scha_board(request): - return render(request, "schasite/scha_board.html", {}) \ No newline at end of file + return render(request, "schasite/scha_board.html", {})