inital check in

This commit is contained in:
2025-03-07 12:15:48 -06:00
parent 1a571d2f8b
commit cdbbea7711
56 changed files with 1988 additions and 0 deletions

22
manage.py Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'scha.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

0
readme.md Normal file
View File

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
stripe
django
django-adminplus
django-recaptcha

0
scha/__init__.py Normal file
View File

16
scha/asgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
ASGI config for scha project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'scha.settings')
application = get_asgi_application()

133
scha/settings.py Normal file
View File

@@ -0,0 +1,133 @@
"""
Django settings for scha project.
Generated by 'django-admin startproject' using Django 4.2.10.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# 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*'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
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',
]
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',
]
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',
],
},
},
]
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',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
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'
# Recaptcha Stuff
RECAPTCHA_PUBLIC_KEY = '6LesfrkpAAAAAGJ5vYp4KuuGcyfk70HkihCwp3d3'
RECAPTCHA_PRIVATE_KEY = '6LesfrkpAAAAABCcDGli5cZiq1hfS0lfRiXg0mlI'

30
scha/urls.py Normal file
View File

@@ -0,0 +1,30 @@
"""
URL configuration for scha project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
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
from django.conf import settings
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),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

16
scha/wsgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
WSGI config for scha project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'scha.settings')
application = get_wsgi_application()

0
schasite/__init__.py Normal file
View File

192
schasite/admin.py Normal file
View File

@@ -0,0 +1,192 @@
from django.contrib import admin
from .models import UsefulLinks, Membership,CalendarEvent, MembershipServices, AddressModel1, MembershipPerson, MembershipCommittee, CalendarEventAddressModel, Payments
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',)
class MembershipPersonInline(admin.TabularInline):
model = MembershipPerson
extra = 1
readonly_fields = ('id',)
class MembershipCommiteeInline(admin.TabularInline):
model = MembershipCommittee
extra = 1
readonly_fields = ('id',)
class MembershipServicesInline(admin.TabularInline):
model = MembershipServices
extra = 1
readonly_fields = ('id',)
def download_csv_by_members(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',
'first_name',
'last_name',
'email',
'phone_number'
])
for q in queryset:
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
])
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)
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"])
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 "",
])
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)
return response
class MembershipAdmin(admin.ModelAdmin):
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',)
class CalendarEventAdmin(admin.ModelAdmin):
inlines = [CalendarEventAddressInline]
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 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'
])
for q in queryset:
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,
])
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)
return response
class PaymentsAdmin(admin.ModelAdmin):
list_display = ["date", "status", "email"]
search_fields = ['email']
actions=[download_payments]
form = PaymentImport
admin.site.register(UsefulLinks, UsefulLinksAdmin)
admin.site.register(Membership, MembershipAdmin)
admin.site.register(CalendarEvent, CalendarEventAdmin)
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)

6
schasite/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class SchasiteConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'schasite'

101
schasite/forms.py Normal file
View File

@@ -0,0 +1,101 @@
from django import forms
from django.forms import ModelForm
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
# class CaptchaForm(forms.Form):
# captcha = ReCaptchaField(
# public_key=settings.RECAPTCHA_PUBLIC_KEY,
# private_key=settings.RECAPTCHA_PRIVATE_KEY,
# widget=ReCaptchaV3(
# attrs={
# 'required_score':0.85,
# }
# ),
# )
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"]
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')
else:
raise ValidationError('No phone number provided')
class Meta:
model = MembershipPerson
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)
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)
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)
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)
class Meta:
model = MembershipCommittee
fields = [
"block_captain",
"coordinator",
"egg_hunt",
"spring_garage_sale",
"golf_outing",
"ice_cream_social",
"fall_garage_sale",
"halloween_party",
"santa_visit",
"website",
"civic_affair",
"phone_directory",
"no_preference",
]
class ServicesForm(ModelForm):
babysitting = forms.BooleanField(label="Babysitting", required=False)
lawn_mowing = forms.BooleanField(label="Lawn Mowing", required=False)
snow_shoveling = forms.BooleanField(label="Snow Shoveling", required=False)
leaf_raking = forms.BooleanField(label="Leaf Raking", required=False)
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 = [
"babysitting",
"lawn_mowing",
"snow_shoveling",
"leaf_raking",
"petsitting",
"house_sitting",
"other",
"other_desc",
]
class PaymentImport(ModelForm):
pass

View File

@@ -0,0 +1,99 @@
# Generated by Django 4.2.10 on 2024-03-20 13:28
from django.db import migrations, models
import django.db.models.deletion
import phonenumber_field.modelfields
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
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)),
],
),
migrations.CreateModel(
name='Membership',
fields=[
('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',
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)),
],
),
migrations.CreateModel(
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')),
],
),
migrations.CreateModel(
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')),
],
),
migrations.CreateModel(
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')),
],
),
migrations.CreateModel(
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')),
],
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.10 on 2024-03-20 15:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('schasite', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='membership',
name='children',
field=models.CharField(blank=True, default='', max_length=256, null=True),
),
]

View File

@@ -0,0 +1,78 @@
# Generated by Django 4.2.10 on 2024-03-20 15:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('schasite', '0002_alter_membership_children'),
]
operations = [
migrations.AlterField(
model_name='membershipcommittee',
name='block_captain',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='civic_affair',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='coordinator',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='egg_hunt',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='fall_garage_sale',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='golf_outing',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='halloween_party',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='ice_cream_social',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='no_preference',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='phone_directory',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='santa_visit',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='spring_garage_sale',
field=models.BooleanField(blank=True, default=False, null=True),
),
migrations.AlterField(
model_name='membershipcommittee',
name='website',
field=models.BooleanField(blank=True, default=False, null=True),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.2.10 on 2024-03-22 13:40
from django.db import migrations
import phonenumber_field.modelfields
class Migration(migrations.Migration):
dependencies = [
('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),
),
]

View File

@@ -0,0 +1,29 @@
# Generated by Django 4.2.10 on 2024-03-22 14:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('schasite', '0004_alter_membershipperson_phone_number'),
]
operations = [
migrations.CreateModel(
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')),
],
),
]

View File

@@ -0,0 +1,37 @@
# Generated by Django 4.2.10 on 2024-03-23 18:03
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('schasite', '0005_membershipservices'),
]
operations = [
migrations.CreateModel(
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)),
],
),
migrations.RemoveField(
model_name='calendarevent',
name='location_address',
),
migrations.DeleteModel(
name='AddressModel',
),
migrations.AddField(
model_name='calendareventaddressmodel',
name='calendar_event',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.calendarevent'),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.2.10 on 2024-03-27 17:40
import datetime
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('schasite', '0006_calendareventaddressmodel_and_more'),
]
operations = [
migrations.CreateModel(
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')),
],
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.2.10 on 2024-03-27 17:41
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('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)),
),
]

View File

128
schasite/models.py Normal file
View File

@@ -0,0 +1,128 @@
from django.db import models
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)
url = models.CharField(max_length=256)
class Membership(models.Model):
children = models.CharField(max_length=256, default="", blank=True, null=True)
def get_address_str(self):
if self.addressmodel1 is None:
return "No Address"
elif self.addressmodel1.address_1 is None:
return "No Address"
else:
return self.addressmodel1.address_1
def get_person_1(self):
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:
return "No Person"
else:
return " | ".join(filtered_emails)
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)
class CalendarEvent(models.Model):
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(max_length=256, blank=True, null=True)
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)
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)
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)
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)
email = models.EmailField(max_length=254, blank=True, null=True)
def __str__(self):
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)
coordinator = models.BooleanField(default=False, blank=True, null=True)
egg_hunt = models.BooleanField(default=False, blank=True, null=True)
spring_garage_sale = models.BooleanField(default=False, blank=True, null=True)
golf_outing = models.BooleanField(default=False, blank=True, null=True)
ice_cream_social = models.BooleanField(default=False, blank=True, null=True)
fall_garage_sale = models.BooleanField(default=False, blank=True, null=True)
halloween_party = models.BooleanField(default=False, blank=True, null=True)
santa_visit = models.BooleanField(default=False, blank=True, null=True)
website = models.BooleanField(default=False, blank=True, null=True)
civic_affair = models.BooleanField(default=False, blank=True, null=True)
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)
lawn_mowing = models.BooleanField(default=False, blank=True, null=True)
snow_shoveling = models.BooleanField(default=False, blank=True, null=True)
leaf_raking = models.BooleanField(default=False, blank=True, null=True)
petsitting = models.BooleanField(default=False, blank=True, null=True)
house_sitting = models.BooleanField(default=False, blank=True, null=True)
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)
email = models.EmailField(blank=True, null=True)
person = models.ForeignKey(MembershipPerson, on_delete=models.CASCADE, blank=True,null=True)

View File

@@ -0,0 +1,156 @@
/* CSS Document */
{% load static %}
body{
margin:0px;
background-repeat: repeat;
font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px;
}
a{color:#63880a;}
h1{
font-family:Arial, Helvetica, sans-serif; font-size:25px;
color:#63880a; line-height:normal;
margin:0px; padding:30px 0px 0px 0px;
}
h1 span{color:#979797;}
.clear{margin:0px; padding:0px; clear:both;}
.top-head{
height:118px; width:1000px; margin:auto;
background:url(../images/top-head.gif) repeat-x;
}
.logo{
height:103px; width:325px;
float:left; padding:15px 0px 0px 55px;
}
.right-top{
height:83px; width:620px; float:left;
padding:35px 0px 0px 0px;
}
.tag-line{
height:auto; width:175px; float:left; padding:0px 10px 0px 20px;
color:#8b8b8b; font-size:11px; font-family:Verdana, Arial, Helvetica, sans-serif;
line-height:22px; border-left:#cad79f solid 1px; text-transform:uppercase; font-weight:bold;
}
.punch-line{
height:auto; width:370px; float:left; padding:0px 20px 0px 20px;
color:#4a4a4a; font-size:11px; font-family:Verdana, Arial, Helvetica, sans-serif;
line-height:22px; border-left:#cad79f solid 1px; font-weight:bold; font-style:italic;
}
.punch-line a{color:#9db54e;}
#header{
height:279px; width:445px; margin:auto;
background:url(../images/header.gif) no-repeat;
padding:40px 500px 0px 55px;
font-family:Verdana, Arial, Helvetica, sans-serif; color:#FFFFFF;
font-size:23px; line-height:26px; font-weight:normal;
}
#header ul{margin:0px; padding:20px 0px 0px 20px;}
#header ul li{
font-family:Verdana, Arial, Helvetica, sans-serif; font-size:13px;
color:#FFFFFF; font-weight:bold;
}
#header ul li a{color:#FFFFFF;}
.nav-bar{
height:56px; width:1000px; margin:auto;
background:url(../images/nav-bar.gif) repeat-x;
}
.nav-bar ul{
margin:0px;
padding:0px 0px 0px 30px;
list-style-type:none;
}
.nav-bar ul li{
height:36px; width:auto; float:left;
background:url(../images/list-left.gif) no-repeat;
display:block;
padding:20px 12px 0px 12px;
}
.nav-bar ul li a{
font-family:Arial, Helvetica, sans-serif; font-size:14px; text-decoration:none;
color:#FFFFFF;
background:url(../images/list-arrow.gif) no-repeat;
font-weight:normal;
padding-left:22px; font-weight:bold;
background-position: 6px;
}
.top-body{
height:auto; width:940px; margin:auto;
background: url(../images/top-body.gif) repeat-x #cfcfcf;
padding:0px 0px 25px 60px;
}
.top-body-con{
height:auto; width:265px; float:left;
padding:0px 35px 0px 0px;
}
.top-body-con p{
margin:0px; padding:30px 0px 0px 0px;
font-family:Verdana, Arial, Helvetica, sans-serif; color:#2e2e2e;
font-size:11px; font-weight:bold; line-height:26px;
}
.top-body-con a{color:#63880a;}
.top-body-con span{color:#63880a; font-size:15px;}
.img-box{
height:auto; width:auto; float:left;
padding:30px 25px 0px 0px;
}
.img-box-1{
height:auto; width:auto; float:right;
padding:20px 0px 0px 25px;
}
.mid-body{
height:auto; width:890px; margin:auto;
background:url(../images/mid-body.gif) repeat-x #FFFFFF;
padding:0px 50px 30px 60px;
}
.mid-body p{
margin:0px; padding:10px 0px 0px 0px;
font-family:Verdana, Arial, Helvetica, sans-serif; color:#343434;
font-size:14px; line-height:26px;
}
.mid-body a{color:#63880a;}
.mid-body p span{color:#343434; font-size:17px;}
.bt-cont{
height:auto; width:930px; margin:auto;
background:url(../images/rest-con.gif) repeat-x #e8edda;
padding:0px 0px 20px 70px;
}
.cont-rl{
height:auto; width:300px; float:left;
}
.bt-cont p{
margin:0px; padding:30px 0px 0px 0px;
font-family:Verdana, Arial, Helvetica, sans-serif; color:#2e2e2e;
font-size:14px; line-height:30px;
}
.bt-cont a{color:#63880a;}
.bt-cont span{color:#63880a; font-size:20px; font-weight:normal;}
#footer{
height:25px; width:880px; margin:auto;
text-align:left; font-family:Verdana, Arial, Helvetica, sans-serif;
color:#FFFFFF; font-size:11px; background:url(../images/footer.gif) repeat-x;
padding:15px 60px 0px 60px;
}
#footer strong{
float:right; color:#FFFFFF;
}
#footer a{ color:#FFFFFF; }
/* inner pages css start */
h1.inner{font:33px Myriad Pro, Arial; color:#fff; font-weight:100; margin:0px; padding:25px 0px 10px 0px; background:none}
.aboutus-img{float:right; border:4px solid #b0a48b; margin:0px 0px 10px 20px;}
h5{font:15px Myriad Pro, Arial, Helvetica, sans-serif; color:#63880a; font-weight:bold; padding:0px 0px 5px 0px; border-bottom:1px dotted #666666; margin:0px 0px 10px 0px;}
h6{font:17px Myriad Pro, Arial, Helvetica, sans-serif; color:#63880a; font-weight:bold; padding:0px 0px 5px 0px; margin:0px 0px 10px 0px;}
.aboutcolumnzone{padding:20px 0px 16px 0px;}
.aboutcolumn1{width:48%; float:left; margin:0px 0px 10px 0px;}
.aboutcolumn2{width:48%; float:right; margin:0px 0px 10px 0px;}
.abouticon{float:left; margin:0px 20px 0px 0px;}
.insidereadmore{padding:10px 0px 10px 0px;}
input.button{color:#ffffff; background:#414141; font:bold 11px Arial, Helvetica, sans-serif; text-decoration:none; padding:10px 10px; margin:0px 5px 5px 0; border:1px solid #000000;}
input.button:hover{cursor:pointer; color:#cccccc;}
.project-img{float:right; margin-left:20px; border: 6px solid #a1b96b;}
.whiteheading{font:30px Myriad Pro, Arial; color:#ffffff; font-weight:100; padding:0px; margin:25px 0px 20px 0px;}
.ourprojectrow{margin-bottom:20px; border-bottom:1px dotted #666666; padding-bottom:10px; width: 95%;}
.servicecolumnzone{padding:20px 0px 16px 0px;}
.servicecolumn1{width:48%; float:left; margin:0px 0px 10px 0px;}
.servicecolumn2{width:48%; float:right; margin:0px 0px 10px 0px;}
.blog-posted-row{padding:3px;}
/* inner pages css ends */

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

24
schasite/static/main.js Normal file
View File

@@ -0,0 +1,24 @@
// static/main.js
console.log("Sanity Check");
fetch("/schasite/config/")
.then((result) => {return result.json(); })
.then((data) => {
const stripe = Stripe(data.publicKey);
// Event Handler
document.querySelector("#submitBtn").addEventListener("click", () => {
// Get Checkout Session ID
fetch("/schasite/create-checkout-session/")
.then((result) => { return result.json(); })
.then((data) => {
console.log(data);
// Redirect to Stripe Checkout
return stripe.redirectToCheckout({sessionId: data.sessionId})
})
.then((res) => {
console.log(res);
});
});
});

View File

@@ -0,0 +1,41 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>About <span>Stonehedge</span></h1>
<div style="padding:10px 0 10px 0">
<div class="clear">
<p><strong>Education</strong></p>
<p align="left">The Stonehedge Subdivision is proud to have excellent public and private schools. The public schools are part of <a href="http://www.cusd200.org/">Community Unit School District 200</a>.&nbsp; Stonehedge subdivision attends:</p>
<p align="left">Whittier Elementary School, 218 W. Park Ave., Wheaton, IL 60189, (630) 682-2185<br />
<a href="http://www.cusd200.org/Domain/1460">Whittier's Web site</a></p>
<p align="left">Edison Middle School, 1125 S. Wheaton Ave., Wheaton, IL 60189, (630) 682-2050<br />
<a href="http://www.cusd200.org/Domain/391">Edison's Web site</a></p>
<p align="left">Wheaton Warrenville South High School, 1920 S. Wiesbrook Rd., Wheaton, IL 60189, (630) 784-7200<br />
<a href="http://www.cusd200.org/Domain/140">WWSHS's Web site</a></p>
<p align="left">There are many private schools in the area as well including Wheaton Christian Grammar School, Wheaton Montessori School, St. John Lutheran School, St. Michael Elementary School, St. Francis High School, Benet Academy and many more.&nbsp;Colleges include Devry, Benedictine, College of DuPage, Wheaton College, IIT, National Louis University, &amp; North Central College.</p>
<p><strong>History</strong></p>
<p align="left">In 1977, Levitt Homes began building the Stonehedge Subdivision.&nbsp; 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.&nbsp; Both Orchard Cove &amp; Marywood were built by Keim.&nbsp; </p>
<p align="left">These 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.</p>
<p align="left"><strong>Shopping</strong></p>
<p align="left">Within walking distance and just east of the subdivisions, there are plenty of shopping centers including Danada East, Danada West, Towne Square &amp; Rice Lake. You'll find supermarkets, post office, banks, restaurants, gas stations, craft stores, department stores, furniture stores, book stores, movie rental stores, dry cleaning facilities, ice cream stores, coffee shops and many other specialty stores.</p>
<p align="left"><strong>Parks &amp; Recreation</strong></p>
<p align="left">The Stonehedge area is ideally suited for recreation. Seven Gables Park, at Brighton and Chatham, is maintained by the Wheaton Park District. It boasts a children's playground, a lake, soccer and baseball fields, picnic shelters, a 1.2 mile paved trail and a fitness course. In addition, there are several smaller parks also located directly within the subdivisions including Ridge Park &amp; Brighton Park. Nearby is the state-of-the-art Rice Water Park and the Wheaton Park District Community Center, which includes a health and fitness center and indoor walking/jogging track and teen center. Arrowhead Golf Course, Herrick Lake, Blackwell Recreation Area, and the Illinois Prairie Path are just west on Butterfield Road.</p>
</div>
</div>
<div class="clear"></div>
</div>
{% endblock %}

View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
{% load static %}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
{% block pagetitle %}
{% endblock %}
<title>Useful Links</title>
<link href="{% static 'css/style.css' %}" rel="stylesheet" type="text/css" />
<style type="text/css">
</style></head>
<body style="background-image: url('{% static "images/bricks.jpg"" %}');">
<div id="header"></div>
<div class="nav-bar">
<ul>
<li><a href="{% url 'index' %}">HOME</a></li>
<li><a href="{% url 'about_us' %}">ABOUT US</a></li>
<li><a href="{% url 'calendar' %}">CALENDAR</a></li>
<li><a href="{% url 'dues' %}">PAY DUES</a></li>
<li><a href="{% url 'membership_form' %}">JOIN TODAY</a></li>
<li><a href="{% url 'scha_board' %}">SCHA BOARD</a></li>
<li><a href="{% url 'useful_links' %}">USEFUL LINKS</a></li>
<li>&nbsp;</li>
</ul>
</div>
{% block content %}
{% endblock %}
<div class="bt-cont">
<div class="cont-rl">
<img src="{% static 'images/memberverification.gif' %}" alt="" class="img-box" />
<p>
<span><a href="pdfs/Members/members2020.pdf">Are you an SCHA member?</a></span><br />
</p>
</div>
<div class="cont-rl">
<img src="{% static 'images/facebook.gif' %}" alt="" class="img-box" />
<p>
<span><a href="https://www.facebook.com/groups/774502395977039/">Like us on facebook</a></span><br />
</p>
</div>
<div class="cont-rl">
<img src="{% static 'images/news.gif' %}" alt="" class="img-box" />
<p>
<span><a href="{% url 'newsletters' %}">Digital <br />
Newsletter</a></span> {# <span><a href="suggestion_box.html"></a></span><br /> #}
</p>
</div>
<div class="clear"></div>
</div>
<div id="footer">&copy; Stonehedge Community Homeowners Association 2010-<script>document.write( new Date().getFullYear() );</script>. All rights reserved
</div>
</body>
</html>

View File

@@ -0,0 +1,90 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Calendar <span>of Events for 2024</span></h1>
<div style="padding:10px 0 10px 0">
<div class="clear">
<h2> Future Events</h2>
{% if future_events %}
{% for event in future_events %}
<h3>{{ event.event_name }} </h3>
{% if event.start_date == event.end_date %}
<p>Date: {{ event.start_date }}</p>
{% else %}
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
{% endif %}
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
{% if event.coordinator_email %}
<p>Coordinator: {{ event.coordinator_email }}</p>
{% endif %}
{% if event.event_url and event.event_link_name %}
<p><a href="{{ event.url }}">{{ event.event_link_name }}</a></p>
{% endif %}
{% endfor %}
{% else %}
<p> Stay tuned for more events!</p>
{% endif %}
<h2>Past Events</h2>
{% if past_events %}
{% for event in past_events %}
<h3>{{ event.event_name }} </h3>
{% if event.start_date == event.end_date %}
<p>Date: {{ event.start_date }}</p>
{% else %}
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
{% endif %}
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
{% if event.coordinator_email %}
<p>Coordinator: {{ event.coordinator_email }}</p>
{% endif %}
{% if event.event_url and event.event_link_name %}
<p><a href="{{ event.url }}">{{ event.event_link_name }}</a></p>
{% endif %}
{% endfor %}
{% else %}
<p> Stay tuned for more events!</p>
{% endif %}
<!-- <p>Membership Drive: Ongoing</p>
<p>Easter Egg Hunt: TBD at Brighton Park</p>
<p>Spring Garage Sale: TBD</p>
<p>Ice Cream Social: TBD at Brighton Park<p>
<p>Stonehedge Sandbagger Scramble: TBD at Arrowhead Golf Course
<p>Fall Garage Sale: TBD</p>
<p>1st Annual Witches and Warlocks Halloween Ride: TBD</p>
<p>Annual Meeting: November TBD </p>
<p>Santa Visits: December TBD</p>
<p>Holiday Decorating Contest: December TBD</p> -->
<p><b>Event Feedack Coming Soon!</b></p>
</div>
</div>
<div class="clear"></div>
</div>
{% endblock %}

View File

@@ -0,0 +1,23 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<script src="https://js.stripe.com/v3/"></script>
<script src="{% static 'main.js' %}"></script>
<div class="mid-body">
<h1>Dues <span>Coming soon!</span></h1>
<button class="button is-primary" id="submitBtn">Pay Dues</button>
</div>
{% endblock %}

View File

@@ -0,0 +1,17 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Your payment cancelled.</h1>
</div>
{% endblock %}

View File

@@ -0,0 +1,17 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Your payment succeeded.</h1>
</div>
{% endblock %}

View File

@@ -0,0 +1,79 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Stonehedge <span>Community Homeowners Association</span></h1>
<div style="padding:10px 0 10px 0">
<div>Thank you for visiting our web site. This is the official Web site for the Stonehedge Community Homeowners Association serving Stonehedge, Golden Pond and Marywood of Wheaton, Illinois. We are located west of Naperville Road and North of Butterfield Road. <br />
<br />
<br />
<div class="clear"></div>
</div>
<div class="clear"></div>
<div class="clear"></div>
<div class="aboutcolumnzone">
<div class="clear"></div>
<div class="aboutcolumn1">
<div>
<h5>Spring Garage Sale</h5>
<img src="{% static 'images/garage_sale.gif' %}" alt="" class="abouticon" />Ready to do some spring cleaning? Check back for the SCHA Spring Garage Sale dates and registration form.
<div class="insidereadmore"><a href="{% url 'calendar' %}">More Information</a></div>
</div>
</div>
<div class="aboutcolumn2">
<div>
<h5>Easter Egg Hunt</h5>
<img src="{% static 'images/easter.gif' %}" alt="" class="abouticon" />Bring the kids for our annual Easter Egg Hunt. More details coming soon.
<div class="insidereadmore"><a href="{% url 'calendar' %}" >More Information</a></div>
</div>
</div>
<div class="clear"></div>
<div class="aboutcolumn1">
<div>
<h5>Join Today</h5>
<img src="{% static 'images/jointoday.gif' %}" alt="" class="abouticon" />Become a Stonehedge member and your membership dues help to fund our family friendly, fun activities and to maintain our beautiful entry drives.
<div class="insidereadmore"><a href="{% url 'membership_form' %}">More Information</a></div>
</div>
</div>
<div class="aboutcolumn2">
<div>
<h5>Drive Safely!</h5>
<img src="{% static 'images/25.gif' %}" alt="" class="abouticon" />This is a friendly reminder that the speed limit in the subdivision is 25. Drive safely and watch for children and pets.
</div>
</div>
<div class="clear"></div>
</div>
</div>
</div>
</div>
<!--<h5>Cromwell Connector Trail</h5>
<img src="images/tree.gif" alt="" class="abouticon" />Learn about new and upcoming DuPage County Forest Preserve projects including the Cromwell Connector Trail.
<div class="insidereadmore"><a href="http://schawheaton.com/dupageforestpreserve.html">More Information</a></div>
</div>
</div>-->
{% endblock %}

View File

@@ -0,0 +1,97 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Membership <span>Form for 2024</span></h1>
<div style="padding:10px 0 10px 0">
<div class="clear">
<form method="POST" action='{% url "membership_form" %}'>
{% csrf_token %}
<div class="aboutcolumnzone">
<div class="aboutcolumn1">
<h5>Person #1</h5>
{% for field in peopleForm1 %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} : {{ field }}
</div>
{% endfor %}
</div>
<div class="aboutcolumn2">
<h5>Person #2</h5>
{% for field in peopleForm2 %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} : {{ field }}
</div>
{% endfor %}
</div>
</div>
<div class="aboutcolumnzone">
<div class="aboutcolumn1">
<h5>Address</h5>
{% for field in addressForm %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} : {{ field }}
</div>
{% endfor %}
<h5>Children</h5>
{% for field in membershipForm %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} : {{ field }}
</div>
<p>Please add the names as a comma seperated list. i.e. Bob, Cindy</p>
{% endfor %}
<h5>Services Information</h5>
{% for field in servicesForm %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field }} : {{ field.label_tag }}
</div>
{% endfor %}
</div>
<div class="aboutcolumn2">
<h5>Committee Information</h5>
{% for field in committeeForm %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field }} : {{ field.label_tag }}
</div>
{% endfor %}
</div>
</div>
<div class="clear"></div>
{% if err_msg %}
<div>
<p>{{ err_msg }}</p>
</div>
{% endif %}
{% if captchaForm %}
{{ captchaForm }}
{% endif %}
<button type=""button" value="submit">Submit</button>
</form>
</div>
<p><strong>Please note dues will be $30 for 2024.</strong></p>
</div>
</div>
</div>
<div class="clear"></div>
{% endblock %}

View File

@@ -0,0 +1,86 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Newsletters</h1>
<div style="padding:10px 0 10px 0">
<div class="clear">
<p><a href="pdfs/Newsletters/MarchApril2020.pdf">March/April 2020</a> (pdf)</p>
<p><a href="pdfs/Newsletters/Jan2020.pdf">January 2020</a> (pdf)</p>
<p><a href="pdfs/Newsletters/NovDec2019.pdf">November/December 2019</a> (pdf)</p>
<p><a href="pdfs/Newsletters/Oct2019.pdf">October 2019</a> (pdf)</p>
<p><a href="pdfs/Newsletters/Sept2019.pdf">September 2019</a> (pdf)</p>
<p><a href="pdfs/Newsletters/Aug19.pdf">August 2019</a> (pdf)</p>
<p><a href="pdfs/Newsletters/July2019.pdf">July 2019</a> (pdf)</p>
<p><a href="pdfs/Newsletters/NovDec2016News.pdf">November/December 2016</a> (pdf)</p>
<p><a href="pdfs/Newsletters/SeptOct2016v2.pdf">September/October 2016</a> (pdf)</p>
<p><a href="pdfs/Newsletters/JulAug2016.pdf">July/August 2016</a> (pdf) Inserts: <a href="pdfs/IceCream/icecreamsmash2016.pdf">Ice Cream Smash</a> &amp; <a href="pdfs/GolfOuting/SCHAGolfOuting2016.pdf">Sandbagger Scramble</a></p>
<p><a href="pdfs/Newsletters/MayJune2016.pdf">May/June 2016</a> (pdf) </p>
<p><a href="pdfs/Newsletters/MarApr16.pdf">March/April 2016</a> (pdf) Inserts: <a href="pdfs/MembershipForms/2016MembershipForm.pdf">2016 Membership Form</a> &amp; <a href="pdfs/BlockCaptains/2016.pdf">Block Captain Thank You</a></p>
<p><a href="pdfs/Newsletters/JanFeb2016.pdf">January/February 2016</a> (pdf) Inserts: <a href="pdfs/MembershipForms/2016MembershipForm.pdf">2016 Membership Form</a> &amp; <a href="pdfs/HolidayDoors2015.pdf">Holiday Doors</a></p>
<p><a href="pdfs/Newsletters/NovDec2015.pdf">November/December 2015</a> (pdf) </p>
<p><a href="pdfs/Newsletters/SeptOct2015.pdf">September/October 2015</a> (pdf) Inserts: <a href="pdfs/garagesale/Fall15.pdf">Garage Sale Flyer</a></p>
<p><a href="pdfs/Newsletters/JulyAug2015.pdf">July/August 2015</a> (pdf) Inserts: <a href="pdfs/garagesale/fall2015.pdf">Garage Sale Flyer</a> &amp; <a href="pdfs/gardenclub/gardenwalk0715.pdf">Garden Walk</a></p>
<p><a href="pdfs/Newsletters/MayJune2015.pdf">May/June 2015</a> (pdf)</p>
<p><a href="pdfs/Newsletters/MarApr2015.pdf">March/April 2015</a> (pdf) Inserts: <a href="pdfs/garagesale/spring15.pdf">Garage Sale Flyer</a> &amp; <a href="pdfs/GolfOuting/SCHAGolfOuting2015.pdf">Golf Outing Flyer</a></p>
<p><a href="pdfs/Newsletters/JanFeb2015.pdf">January/February 2015</a> (pdf) </p>
<p><a href="pdfs/MembershipForms/2015.pdf">January 2015 - Annual Membership Form</a> (pdf) </p>
<p><a href="pdfs/Newsletters/NovDec2014.pdf">November/December 2014</a> (pdf) </p>
<p><a href="pdfs/Newsletters/SeptOct2014.pdf">September/October 2014</a> (pdf) Inserts: <a href="pdfs/garagesale/Fall2014.pdf">garage sale flyer</a></p>
<p><a href="pdfs/Newsletters/JulAug2014.pdf">July/August 2014</a> (pdf) </p>
<p><a href="pdfs/Newsletters/MayJune2014.pdf">May/June 2014</a> (pdf) Inserts: <a href="pdfs/MembershipForms/membership.pdf">membership form</a> &amp; <a href="pdfs/garagesale/garage_sale_spring2014 .pdf">garage sale flyer</a></p>
<p><a href="pdfs/Newsletters/MarApr2014.pdf">March/April 2014</a> (pdf)</p>
<p><a href="pdfs/Newsletters/JanFeb2014.pdf">Jan/Feb 2014</a> (pdf)</p>
<p><a href="pdfs/Newsletters/NovDec2013.pdf">November/December 2013</a> (pdf)</p>
<p><a href="pdfs/Newsletters/SeptOct2013.pdf">September/October 2013</a> (pdf)</p>
<p><a href="pdfs/Newsletters/JulAug2013.pdf">July/August 2013</a> (pdf)</p>
<p><a href="pdfs/Newsletters/MayJune2013.pdf">May/June 2013</a> (pdf)</p>
<p><a href="pdfs/Newsletters/MarApr2013.pdf">March/April 2013</a> (pdf)</p>
<p><a href="pdfs/Newsletters/JanFeb2013.pdf">January/February 2013</a> (pdf) </p>
<h1><strong><em>Interested in advertising in our newsletter?</em></strong></h1>
<p><strong>Advertising Rates: </strong><br />
1/4 page: $70<br />
1/2 page: $90 <br />
Full page: $175</p>
<p><strong>Issue Deadlines:</strong><br />
July/August - July 3<br />
September/October - September 1<br />
November/December - November 1 <br />
</p>
</div>
</div>
<div class="clear"></div>
</div>
{% endblock %}

View File

@@ -0,0 +1,77 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>SCHA <span>Board Members for 2022</span></h1>
<div style="padding:10px 0 10px 0">
<table width="565" border="1" cellspacing="0" cellpadding="1">
<tr>
<td width="167"><p>Monica Dhillon</p></td>
<td width="196"><p>President</p></td>
<td width="202"><p><a href="mailto:moni.dhill@gmail.com">moni.dhill@gmail.com</a></p></td>
</tr>
<tr>
<td><p>Teresa Westfall</p></td>
<td><p>1st Vice President</p></td>
<td width="202"><p><a href="mailto:teresa.westfall299@gmail.com">teresa.westfall299@gmail.com</a></p></td>
</tr>
<tr>
<td><p>Tom Hatting</p></td>
<td><p>2nd Vice President</p></td>
<td><p><a href="mailto:tmhatting@comcast.net">tmhatting@comcast.net</a></p></td>
</tr>
<tr>
<td><p>Chris Cozart</p></td>
<td><p>Treasurer</p></td>
<td><p><a href="mailto:cdcozart@aol.com">cdcozart@aol.com</a></p></td>
</tr>
<tr>
<td><p>Anna Malik</p></td>
<td><p>Secretary</p></td>
<td><p><a href="mailto:Malik.anusha@gmail.com">Malik.anusha@gmail.com</a></p></td>
</tr>
<tr>
<td><p>Jill Feitl</p></td>
<td><p>Web site</p></td>
<td><p><a href="mailto:jfeitl@hotmail.com">jfeitl@hotmail.com</a></p></td>
</tr>
<tr>
<td><p>Wendy Peck</p></td>
<td><p>Membership</p></td>
<td><p><a href="wlpeck116@gmail.com">wlpeck116@gmail.com</a></p></td>
</tr>
<tr>
<td><p>Melissa Gonski<br>
Mike Joyce</p></td>
<td><p>Directory</p></td>
<td><p><a href="mailto:melissagonski@gmail.com">melissagonski@gmail.com</a><br>
<a href="mailto:mike.joyce@bairdwarner.com">mike.joyce@bairdwarner.com</a>
</p></td>
</tr>
<tr>
<td><p>Pat Hanika</p></td>
<td><p>Facebook</p></td>
<td><p><a href="mailto:pathanika@gmail.com">pathanika@gmail.com</a></p></td>
</tr>
<tr>
<td><p>Stephanie Bakula</p></td>
<td><p>Eblasts</p></td>
<td><p><a href="mailto:sabakula@gmail.com">sabakula@gmail.com</a></p></td>
</tr>
</table>
</div>
</span>
</div>
{% endblock %}

View File

@@ -0,0 +1,29 @@
{% extends 'schasite/base.html' %}
{% load static %}
{% block pagetitle %}
<title>Useful Links</title>
{% endblock %}
{% block content %}
<div class="mid-body">
<h1>Useful <span>Links</span></h1>
<div style="padding:10px 0 10px 0">
<div class="clear">
{% if links %}
{% for link in links %}
<p><a href="{{ link.url }}">{{ link.name }}</a></p>
{% endfor %}
{% endif %}
</div>
</div>
<div class="clear"></div>
</div>
{% endblock %}

3
schasite/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

17
schasite/urls.py Normal file
View File

@@ -0,0 +1,17 @@
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("useful_links", views.useful_links, name="useful_links"),
path("about_us", views.about_us, name="about_us"),
path("calendar", views.calendar, name="calendar"),
path("newsletters", views.newsletters, name="newsletters"),
path("dues", views.dues, name="dues"),
path("membership_form", views.membership_form, name="membership_form"),
path("scha_board", views.scha_board, name="scha_board"),
# stripe specific urls below
path('config/', views.stripe_config),
path('create-checkout-session/', views.create_checkout_session),
]

199
schasite/views.py Normal file
View File

@@ -0,0 +1,199 @@
from django.shortcuts import render, redirect
from .models import UsefulLinks, CalendarEvent, MembershipPerson, Payments
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.http.response import JsonResponse, HttpResponse
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}
return JsonResponse(stripe_config, safe=False)
@csrf_exempt
def create_checkout_session(request):
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'],
mode="payment",
line_items = [{
# 'name':'SCHA Dues',
'quantity': 1,
# 'currency': 'usd',
'price': 'price_1OxZLfDV0RPXOyxG5ipjhUXk',
}]
)
return JsonResponse({'sessionId': checkout_session['id']})
except Exception as 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']
event = None
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# Handle the checkout.session.completed event
if event['type'] == 'checkout.session.completed':
email = None
try:
email = event['data']['object']['customer_details']['email']
except:
pass
person = MembershipPerson.objects.filter(email=email).first() # just take the first
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):
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 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", {})