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 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
Rating: 75.69/10 (U.S. News)
+ Grades: 6-8
+ Enrollment: 674
+ Distance: 2.5 miles from community entrance
+ Principal: Rachel Bednar
Rating: 90.43/10 (U.S. News)
+ Grades: 9-12
+ Enrollment: 1845
+ Distance: 3.1 miles from community entrance
+ Principal: Lorie Campos
+ 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.
+Stonehedge Community Homeowners Association is conveniently located near excellent shopping and dining options to meet all your needs.
+ +
+ 1.0 miles from community
+Over 10 stores including major department stores, fashion retailers, and specialty shops.
+
+ 2.7 miles from community
+Fresh local produce, artisanal foods, and handmade goods every Saturday morning.
+
+ 2.8 miles from community
+Fresh local produce, artisanal foods, and handmade goods every Saturday morning.
+
+ 6.2 miles from community
+Diverse restaurants featuring Italian, Asian, Mexican, and American cuisine options.
+
+ Within SCHA
+Open daily from dawn to dusk
+
+ 0.5 miles from SCHA
+66.5 acres featuring sports fields, tennis courts & an ice rink, plus other recreational facilities.
+Open daily from 8am to sunset
+