Compare commits
2
Commits
master
..
9d3159027e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d3159027e | ||
|
|
2081210b78 |
@@ -23,8 +23,5 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DJANGO_ENV: dev
|
DJANGO_ENV: dev
|
||||||
DJANGO_SECRET_KEY: test-secret-key
|
DJANGO_SECRET_KEY: test-secret-key
|
||||||
# Explicitly clear DB vars so host/prod DATABASE_URL cannot leak in.
|
|
||||||
DATABASE_URL: ""
|
|
||||||
DB_HOST: ""
|
|
||||||
run: |
|
run: |
|
||||||
uv run python manage.py test
|
uv run python manage.py test
|
||||||
|
|||||||
@@ -20,27 +20,15 @@ jobs:
|
|||||||
- name: Build Docker image
|
- name: Build Docker image
|
||||||
run: docker compose build
|
run: docker compose build
|
||||||
|
|
||||||
# Ephemeral local Postgres only — never inherit host DATABASE_URL (prod).
|
|
||||||
- name: Run containerized tests
|
- name: Run containerized tests
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
docker compose up -d db
|
||||||
# Drop host/prod DB secrets so compose cannot interpolate them.
|
docker compose run --rm --entrypoint "" \
|
||||||
unset DATABASE_URL DB_HOST DB_NAME DB_USER DB_PASSWORD DB_PORT \
|
|
||||||
COMPOSE_DATABASE_URL DJANGO_ENV DJANGO_SECRET_KEY DJANGO_DEBUG \
|
|
||||||
DJANGO_ALLOWED_HOSTS || true
|
|
||||||
|
|
||||||
PROJECT="scha-ci-${{ gitea.event.workflow_run.head_sha }}"
|
|
||||||
cleanup() { docker compose -p "$PROJECT" down -v --remove-orphans || true; }
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
docker compose -p "$PROJECT" up -d --wait db
|
|
||||||
docker compose -p "$PROJECT" run --rm --no-deps --entrypoint "" \
|
|
||||||
-e DJANGO_ENV=dev \
|
-e DJANGO_ENV=dev \
|
||||||
-e DJANGO_SECRET_KEY=test-secret-key \
|
-e DJANGO_SECRET_KEY=test-secret-key \
|
||||||
-e DJANGO_DEBUG=true \
|
|
||||||
-e DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,testserver \
|
|
||||||
-e DATABASE_URL=postgres://scha:scha@db:5432/scha \
|
-e DATABASE_URL=postgres://scha:scha@db:5432/scha \
|
||||||
web uv run python manage.py test
|
web uv run python manage.py test
|
||||||
|
docker compose down
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
if: gitea.event.workflow_run.conclusion == 'success' && gitea.event.workflow_run.event == 'push'
|
if: gitea.event.workflow_run.conclusion == 'success' && gitea.event.workflow_run.event == 'push'
|
||||||
|
|||||||
@@ -25,8 +25,5 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DJANGO_ENV: dev
|
DJANGO_ENV: dev
|
||||||
DJANGO_SECRET_KEY: test-secret-key
|
DJANGO_SECRET_KEY: test-secret-key
|
||||||
# Explicitly clear DB vars so host/prod DATABASE_URL cannot leak in.
|
|
||||||
DATABASE_URL: ""
|
|
||||||
DB_HOST: ""
|
|
||||||
run: |
|
run: |
|
||||||
uv run python manage.py test
|
uv run python manage.py test
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ Without `DATABASE_URL` / `DB_HOST`, settings fall back to SQLite (`db.sqlite3`).
|
|||||||
docker compose up --build
|
docker compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
App: http://localhost:8000 — Postgres via bundled `db` (`postgres://scha:scha@db:5432/scha`).
|
App: http://localhost:8000 — Postgres via `DATABASE_URL=postgres://scha:scha@db:5432/scha`.
|
||||||
Compose does **not** read host `DATABASE_URL` (avoids CI/prod leaks); override with `COMPOSE_DATABASE_URL` if needed.
|
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
@@ -70,7 +69,7 @@ Validate with:
|
|||||||
|----------|---------|--------|
|
|----------|---------|--------|
|
||||||
| `unittests.yml` | push + PR → `master` | `uv sync` + `manage.py test` |
|
| `unittests.yml` | push + PR → `master` | `uv sync` + `manage.py test` |
|
||||||
| `ci.yml` | PR → `master` | same unit tests |
|
| `ci.yml` | PR → `master` | same unit tests |
|
||||||
| `deploy.yml` | after Unit Tests succeeds on `master` **push** | docker build + tests on **ephemeral compose Postgres** → `deploy.sh` |
|
| `deploy.yml` | after Unit Tests succeeds on `master` **push** | docker build/test → `deploy.sh` |
|
||||||
|
|
||||||
Deploy never runs on PRs.
|
Deploy never runs on PRs.
|
||||||
|
|
||||||
|
|||||||
+1
-5
@@ -20,16 +20,12 @@ services:
|
|||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
# No required env_file — CI has no .env. Defaults below; for local secrets:
|
# No required env_file — CI has no .env. Defaults below; for local secrets:
|
||||||
# docker compose --env-file .env up
|
# docker compose --env-file .env up
|
||||||
#
|
|
||||||
# Do NOT interpolate ${DATABASE_URL} here. On the Act runner / control node that
|
|
||||||
# var often points at shared prod/beta Postgres; compose would bake it into
|
|
||||||
# containerized tests. Use COMPOSE_DATABASE_URL only if you need to override.
|
|
||||||
environment:
|
environment:
|
||||||
DJANGO_ENV: ${DJANGO_ENV:-dev}
|
DJANGO_ENV: ${DJANGO_ENV:-dev}
|
||||||
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-only-change-me}
|
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-only-change-me}
|
||||||
DJANGO_DEBUG: ${DJANGO_DEBUG:-true}
|
DJANGO_DEBUG: ${DJANGO_DEBUG:-true}
|
||||||
DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS:-localhost,127.0.0.1,0.0.0.0}
|
DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS:-localhost,127.0.0.1,0.0.0.0}
|
||||||
DATABASE_URL: ${COMPOSE_DATABASE_URL:-postgres://scha:scha@db:5432/scha}
|
DATABASE_URL: ${DATABASE_URL:-postgres://scha:scha@db:5432/scha}
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ description = "Django site for SCHA Wheaton"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"django>=6.0,<7",
|
"django>=5.2,<6",
|
||||||
"django-phonenumber-field>=8.1.0",
|
"django-phonenumber-field>=8.1.0",
|
||||||
"django-recaptcha>=4.1.0",
|
"django-recaptcha>=4.1.0",
|
||||||
"gunicorn>=23.0.0",
|
"gunicorn>=23.0.0",
|
||||||
|
|||||||
@@ -165,23 +165,10 @@ class CalendarEventAdmin(admin.ModelAdmin):
|
|||||||
list_display = [
|
list_display = [
|
||||||
"event_name",
|
"event_name",
|
||||||
"start_date",
|
"start_date",
|
||||||
"start_time",
|
|
||||||
"end_date",
|
"end_date",
|
||||||
"end_time",
|
|
||||||
"coordinator_email",
|
"coordinator_email",
|
||||||
"event_link_name",
|
"event_link_name",
|
||||||
]
|
]
|
||||||
fields = [
|
|
||||||
"event_name",
|
|
||||||
"start_date",
|
|
||||||
"start_time",
|
|
||||||
"end_date",
|
|
||||||
"end_time",
|
|
||||||
"location_name",
|
|
||||||
"coordinator_email",
|
|
||||||
"event_link_name",
|
|
||||||
"event_url",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class AddressModelAdmin(admin.ModelAdmin):
|
class AddressModelAdmin(admin.ModelAdmin):
|
||||||
|
|||||||
+5
-1
@@ -19,7 +19,11 @@ class CaptchaForm(forms.Form):
|
|||||||
captcha = ReCaptchaField(
|
captcha = ReCaptchaField(
|
||||||
public_key=settings.RECAPTCHA_PUBLIC_KEY,
|
public_key=settings.RECAPTCHA_PUBLIC_KEY,
|
||||||
private_key=settings.RECAPTCHA_PRIVATE_KEY,
|
private_key=settings.RECAPTCHA_PRIVATE_KEY,
|
||||||
widget=ReCaptchaV3(required_score=0.85),
|
widget=ReCaptchaV3(
|
||||||
|
attrs={
|
||||||
|
'required_score':0.85,
|
||||||
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
# Generated by Django 5.2.16 on 2026-07-14 12:06
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.utils.timezone
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('schasite', '0010_communityparks_communitypost_communityschools_and_more'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='payments',
|
|
||||||
name='date',
|
|
||||||
field=models.DateField(default=datetime.datetime(2026, 7, 14, 12, 6, 52, 688298, tzinfo=datetime.timezone.utc)),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='CommunityMember',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('created', models.DateTimeField(default=django.utils.timezone.now)),
|
|
||||||
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
|
|
||||||
('membership_person', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.membershipperson')),
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='communitycomment',
|
|
||||||
name='author',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='schasite.communitymember'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='communitypost',
|
|
||||||
name='author',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='schasite.communitymember'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='communitypostreports',
|
|
||||||
name='reporter',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='schasite.communitymember'),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='CommunityPostLikes',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('created', models.DateTimeField(default=django.utils.timezone.now)),
|
|
||||||
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
|
|
||||||
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='schasite.communitypost')),
|
|
||||||
('reporter', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='schasite.communitymember')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 6.0.7 on 2026-07-14 12:13
|
|
||||||
|
|
||||||
import django.utils.timezone
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('schasite', '0011_alter_payments_date_communitymember_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='payments',
|
|
||||||
name='date',
|
|
||||||
field=models.DateField(default=django.utils.timezone.now),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 6.0.7 on 2026-08-04 17:59
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('schasite', '0012_alter_payments_date'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='calendarevent',
|
|
||||||
name='end_time',
|
|
||||||
field=models.TimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='calendarevent',
|
|
||||||
name='start_time',
|
|
||||||
field=models.TimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
+6
-21
@@ -12,13 +12,13 @@ class TimeInfoBase(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not kwargs.pop("skip_last_modified", False) and not hasattr(self, "skip_last_modified"):
|
if not kwargs.pop("skip_last_modified", False) and not hasattr(self, "skip_last_modified"):
|
||||||
self.last_modified = timezone.now()
|
self.last_modified = timezone.now()
|
||||||
if kwargs.get("update_fields") is not None:
|
if kwargs.get("update_fields") is not None:
|
||||||
kwargs["update_fields"] = list({*kwargs["update_fields"], "last_modified"})
|
kwargs["update_fields"] = list({*kwargs["update_fields"], "last_modified"})
|
||||||
|
|
||||||
super().save(**kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
class UsefulLinks(TimeInfoBase):
|
class UsefulLinks(TimeInfoBase):
|
||||||
@@ -66,8 +66,6 @@ class CalendarEvent(TimeInfoBase):
|
|||||||
event_name = models.CharField(max_length=256)
|
event_name = models.CharField(max_length=256)
|
||||||
start_date = models.DateField(blank=True, null=True)
|
start_date = models.DateField(blank=True, null=True)
|
||||||
end_date = models.DateField(blank=True, null=True)
|
end_date = models.DateField(blank=True, null=True)
|
||||||
start_time = models.TimeField(blank=True, null=True)
|
|
||||||
end_time = models.TimeField(blank=True, null=True)
|
|
||||||
location_name = models.CharField(max_length=256, 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)
|
coordinator_email = models.EmailField(max_length=256, blank=True, null=True)
|
||||||
event_link_name = models.CharField(max_length=64, blank=True, null=True)
|
event_link_name = models.CharField(max_length=64, blank=True, null=True)
|
||||||
@@ -92,19 +90,6 @@ class CalendarEvent(TimeInfoBase):
|
|||||||
def no_date(self):
|
def no_date(self):
|
||||||
return not self.has_date()
|
return not self.has_date()
|
||||||
|
|
||||||
def time_range_display(self):
|
|
||||||
"""Format start/end times for templates, e.g. '11:00 AM - 3:00 PM'."""
|
|
||||||
from django.utils.formats import time_format
|
|
||||||
|
|
||||||
if not self.start_time and not self.end_time:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
start = time_format(self.start_time, "g:i A") if self.start_time else ""
|
|
||||||
end = time_format(self.end_time, "g:i A") if self.end_time else ""
|
|
||||||
if start and end:
|
|
||||||
return f"{start} - {end}"
|
|
||||||
return start or end
|
|
||||||
|
|
||||||
|
|
||||||
class CalendarEventAddressModel(TimeInfoBase):
|
class CalendarEventAddressModel(TimeInfoBase):
|
||||||
calendar_event = models.OneToOneField(CalendarEvent, on_delete=models.CASCADE)
|
calendar_event = models.OneToOneField(CalendarEvent, on_delete=models.CASCADE)
|
||||||
@@ -163,7 +148,7 @@ class MembershipServices(TimeInfoBase):
|
|||||||
|
|
||||||
|
|
||||||
class Payments(TimeInfoBase):
|
class Payments(TimeInfoBase):
|
||||||
date = models.DateField(default=timezone.now)
|
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)
|
email = models.EmailField(blank=True, null=True)
|
||||||
person = models.ForeignKey(
|
person = models.ForeignKey(
|
||||||
@@ -209,12 +194,12 @@ class CommunityPost(TimeInfoBase):
|
|||||||
category = models.CharField(max_length=255)
|
category = models.CharField(max_length=255)
|
||||||
content = models.CharField(max_length=1024*8)
|
content = models.CharField(max_length=1024*8)
|
||||||
likes = models.IntegerField(default=0)
|
likes = models.IntegerField(default=0)
|
||||||
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE, blank=True, null=True)
|
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class CommunityPostReports(TimeInfoBase):
|
class CommunityPostReports(TimeInfoBase):
|
||||||
# for anyone who reports a post
|
# for anyone who reports a post
|
||||||
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
||||||
reporter = models.OneToOneField(CommunityMember, on_delete=models.CASCADE, blank=True, null=True)
|
reporter = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class CommunityPostLikes(TimeInfoBase):
|
class CommunityPostLikes(TimeInfoBase):
|
||||||
# for anyone who likes a post
|
# for anyone who likes a post
|
||||||
@@ -225,4 +210,4 @@ class CommunityComment(TimeInfoBase):
|
|||||||
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
||||||
content = models.CharField(max_length=1024*8)
|
content = models.CharField(max_length=1024*8)
|
||||||
likes = models.IntegerField(default=0)
|
likes = models.IntegerField(default=0)
|
||||||
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE, blank=True, null=True)
|
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
/* CSS Document */
|
/* CSS Document */
|
||||||
|
{% load static %}
|
||||||
body{
|
body{
|
||||||
margin:0px;
|
margin:0px;
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
@@ -12,6 +13,10 @@ h1{
|
|||||||
}
|
}
|
||||||
h1 span{color:#979797;}
|
h1 span{color:#979797;}
|
||||||
.clear{margin:0px; padding:0px; clear:both;}
|
.clear{margin:0px; padding:0px; clear:both;}
|
||||||
|
.top-head{
|
||||||
|
height:118px; width:1000px; margin:auto;
|
||||||
|
background:url(../images/top-head.gif) repeat-x;
|
||||||
|
}
|
||||||
.logo{
|
.logo{
|
||||||
height:103px; width:325px;
|
height:103px; width:325px;
|
||||||
float:left; padding:15px 0px 0px 55px;
|
float:left; padding:15px 0px 0px 55px;
|
||||||
@@ -67,6 +72,22 @@ h1 span{color:#979797;}
|
|||||||
padding-left:22px; font-weight:bold;
|
padding-left:22px; font-weight:bold;
|
||||||
background-position: 6px;
|
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{
|
.img-box{
|
||||||
height:auto; width:auto; float:left;
|
height:auto; width:auto; float:left;
|
||||||
padding:30px 25px 0px 0px;
|
padding:30px 25px 0px 0px;
|
||||||
|
|||||||
@@ -10,28 +10,9 @@ section {
|
|||||||
scroll-margin-top: 70px;
|
scroll-margin-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip link visible when focused */
|
|
||||||
.visually-hidden-focusable:focus {
|
|
||||||
z-index: 1080;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reserve image space to reduce CLS */
|
|
||||||
.card-img-top {
|
|
||||||
aspect-ratio: 16 / 9;
|
|
||||||
object-fit: cover;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.img-fluid {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hero Section */
|
/* Hero Section */
|
||||||
#home {
|
#home {
|
||||||
background-color: rgba(var(--bs-success-rgb), 0.1);
|
background-color: rgba(var(--bs-success-rgb), 0.1);
|
||||||
min-height: 280px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* News and Contact Sections */
|
/* News and Contact Sections */
|
||||||
@@ -62,4 +43,4 @@ img.img-fluid {
|
|||||||
.was-validated .form-control:valid,
|
.was-validated .form-control:valid,
|
||||||
.form-control.is-valid {
|
.form-control.is-valid {
|
||||||
border-color: #198754;
|
border-color: #198754;
|
||||||
}
|
}
|
||||||
@@ -2,31 +2,16 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>About Us | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Learn about Stonehedge in Wheaton, IL — local schools, community history, shopping and dining nearby, and parks that serve residents.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}About Us | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Learn about Stonehedge in Wheaton, IL — local schools, community history, shopping and dining nearby, and parks that serve residents.{% endblock %}
|
|
||||||
{% block twitter_title %}About Us | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Learn about Stonehedge in Wheaton, IL — local schools, community history, shopping and dining nearby, and parks that serve residents.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<section class="py-4 bg-success bg-opacity-10">
|
|
||||||
<div class="container">
|
|
||||||
<h1 class="text-success mb-0">About Stonehedge</h1>
|
|
||||||
<p class="lead mb-0 mt-2">Schools, history, nearby amenities, and parks serving our Wheaton community.</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="schools" class="py-5">
|
<section id="schools" class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div class="col-lg-6 mb-4 mb-lg-0">
|
<div class="col-lg-6 mb-4 mb-lg-0">
|
||||||
<img src="{% static 'images/District_200.png' %}" alt="Community Unit School District 200 logo" class="img-fluid rounded shadow" width="600" height="400">
|
<img src="{% static 'images/District_200.png' %}" alt="Local Schools" class="img-fluid rounded shadow">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<h2 class="text-success mb-4">Excellent Schools Serving Our Community</h2>
|
<h2 class="text-success mb-4">Excellent Schools Serving Our Community</h2>
|
||||||
@@ -142,7 +127,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div class="col-lg-6 order-lg-2 mb-4 mb-lg-0">
|
<div class="col-lg-6 order-lg-2 mb-4 mb-lg-0">
|
||||||
<img src="{% static 'images/header.gif' %}" alt="Historic view of the Stonehedge community" class="img-fluid rounded shadow" width="600" height="400">
|
<img src="{% static 'images/header.gif' %}" alt="Community History" class="img-fluid rounded shadow">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 order-lg-1">
|
<div class="col-lg-6 order-lg-1">
|
||||||
<h2 class="text-success mb-4">Our Rich History</h2>
|
<h2 class="text-success mb-4">Our Rich History</h2>
|
||||||
@@ -176,7 +161,7 @@
|
|||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<img src="{% static 'images/danada.jpeg' %}" class="card-img-top" alt="Danada Square shopping area" width="640" height="360">
|
<img src="{% static 'images/danada.jpeg' %}" class="card-img-top" alt="Greenwood Mall">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Danada</h5>
|
<h5 class="card-title">Danada</h5>
|
||||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>1.0 miles from community</p>
|
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>1.0 miles from community</p>
|
||||||
@@ -189,7 +174,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<img src="{% static 'images/downtown_wheaton.jpeg' %}" class="card-img-top" alt="Downtown Wheaton streetscape" width="640" height="360">
|
<img src="{% static 'images/downtown_wheaton.jpeg' %}" class="card-img-top" alt="Farmers Market">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Downtown Wheaton</h5>
|
<h5 class="card-title">Downtown Wheaton</h5>
|
||||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.7 miles from community</p>
|
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.7 miles from community</p>
|
||||||
@@ -203,7 +188,7 @@
|
|||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<img src="{% static 'images/wheaton_farmers_market.jpeg' %}" class="card-img-top" alt="Wheaton Farmers Market stalls" width="640" height="360">
|
<img src="{% static 'images/wheaton_farmers_market.jpeg' %}" class="card-img-top" alt="Farmers Market">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Wheaton Farmersmarket</h5>
|
<h5 class="card-title">Wheaton Farmersmarket</h5>
|
||||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.8 miles from community</p>
|
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.8 miles from community</p>
|
||||||
@@ -216,7 +201,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<img src="{% static 'images/downtown_naperville.jpeg' %}" class="card-img-top" alt="Downtown Naperville dining district" width="640" height="360">
|
<img src="{% static 'images/downtown_naperville.jpeg' %}" class="card-img-top" alt="Dining District">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Downtown Naperville</h5>
|
<h5 class="card-title">Downtown Naperville</h5>
|
||||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>6.2 miles from community</p>
|
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>6.2 miles from community</p>
|
||||||
@@ -242,7 +227,7 @@
|
|||||||
<div class="card shadow-sm h-100">
|
<div class="card shadow-sm h-100">
|
||||||
<div class="row g-0 h-100">
|
<div class="row g-0 h-100">
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<img src="{% static 'images/brighton.jpg' %}" class="img-fluid rounded-start h-100" alt="Brighton Park playground and green space" width="400" height="300" style="object-fit: cover;">
|
<img src="{% static 'images/brighton.jpg' %}" class="img-fluid rounded-start h-100" alt="Community Park" style="object-fit: cover;">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -264,7 +249,7 @@
|
|||||||
<div class="card shadow-sm h-100">
|
<div class="card shadow-sm h-100">
|
||||||
<div class="row g-0 h-100">
|
<div class="row g-0 h-100">
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<img src="{% static 'images/seven_gables.jpg' %}" class="img-fluid rounded-start h-100" alt="Seven Gables Park nature preserve" width="400" height="300" style="object-fit: cover;">
|
<img src="{% static 'images/seven_gables.jpg' %}" class="img-fluid rounded-start h-100" alt="Nature Preserve" style="object-fit: cover;">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|||||||
@@ -5,22 +5,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Stonehedge Community Homeowners Association | Wheaton, IL</title>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Stonehedge Community Homeowners Association in Wheaton, Illinois — community news, events, dues, membership, and board information for residents.">
|
|
||||||
{% endblock %}
|
|
||||||
<link rel="canonical" href="{{ request.scheme }}://{{ request.get_host }}{{ request.path }}">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
<meta property="og:site_name" content="Stonehedge Community Homeowners Association">
|
|
||||||
<meta property="og:locale" content="en_US">
|
|
||||||
<meta property="og:url" content="{{ request.scheme }}://{{ request.get_host }}{{ request.path }}">
|
|
||||||
<meta property="og:title" content="{% block og_title %}Stonehedge Community Homeowners Association | Wheaton, IL{% endblock %}">
|
|
||||||
<meta property="og:description" content="{% block og_description %}Stonehedge Community Homeowners Association in Wheaton, Illinois — community news, events, dues, membership, and board information for residents.{% endblock %}">
|
|
||||||
<meta name="twitter:card" content="summary">
|
|
||||||
<meta name="twitter:title" content="{% block twitter_title %}Stonehedge Community Homeowners Association | Wheaton, IL{% endblock %}">
|
|
||||||
<meta name="twitter:description" content="{% block twitter_description %}Stonehedge Community Homeowners Association in Wheaton, Illinois — community news, events, dues, membership, and board information for residents.{% endblock %}">
|
|
||||||
<link rel="alternate" type="text/plain" title="LLM site guidance" href="{% url 'llms_txt' %}">
|
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<!-- Bootstrap Icons -->
|
<!-- Bootstrap Icons -->
|
||||||
@@ -31,13 +16,12 @@
|
|||||||
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm9qziuid9vr7v6dtdbnx8406"></script>
|
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm9qziuid9vr7v6dtdbnx8406"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<a class="visually-hidden-focusable btn btn-success position-absolute m-2" href="#main-content">Skip to main content</a>
|
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-success sticky-top" aria-label="Primary">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-success sticky-top">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="{% url 'index2' %}">Stonehedge Community Homeowners Association</a>
|
<a class="navbar-brand" href="{% url 'index2' %}">Stonehedge Community Homeowners Association</a>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
@@ -68,10 +52,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<main id="main-content">
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
@@ -79,10 +61,10 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 mb-4 mb-lg-0">
|
<div class="col-lg-6 mb-4 mb-lg-0">
|
||||||
<h2 class="h5 text-uppercase mb-4">Stonehedge Community Homeowners Association</h2>
|
<h5 class="text-uppercase mb-4">Stonehedge Community Homeowners Association</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4 offset-lg-2 mb-4 mb-lg-0">
|
<div class="col-lg-4 offset-lg-2 mb-4 mb-lg-0">
|
||||||
<h2 class="h5 text-uppercase mb-4">Quick Links</h2>
|
<h5 class="text-uppercase mb-4">Quick Links</h5>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li class="mb-2"><a href="{% url 'index2' %}" class="text-white-50 text-decoration-none">Home</a></li>
|
<li class="mb-2"><a href="{% url 'index2' %}" class="text-white-50 text-decoration-none">Home</a></li>
|
||||||
<li class="mb-2"><a href="{% url 'about_us2' %}" class="text-white-50 text-decoration-none">About</a></li>
|
<li class="mb-2"><a href="{% url 'about_us2' %}" class="text-white-50 text-decoration-none">About</a></li>
|
||||||
@@ -97,8 +79,8 @@
|
|||||||
<hr class="my-4 text-white-50">
|
<hr class="my-4 text-white-50">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<p>© Stonehedge Community Homeowners Association 2010-{% now "Y" %}. All rights reserved.</p>
|
<p>© Stonehedge Community Homeowners Association 2010-<script>document.write( new Date().getFullYear() );</script>. All rights reserved </p>
|
||||||
<p> Developed by <a href="https://aimloperations.com" class="text-white-50">AI ML Operations, LLC</a></p>
|
<p> Developed by <a href="https://aimloperations.com">AI ML Operations, LLC</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -23,9 +23,6 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if event.time_range_display %}
|
|
||||||
<p>Time: {{ event.time_range_display }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
||||||
{% if event.coordinator_email %}
|
{% if event.coordinator_email %}
|
||||||
<p>Coordinator: {{ event.coordinator_email }}</p>
|
<p>Coordinator: {{ event.coordinator_email }}</p>
|
||||||
@@ -47,9 +44,6 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
<p>Date: {{ event.start_date }} - {{ event.end_date }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if event.time_range_display %}
|
|
||||||
<p>Time: {{ event.time_range_display }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
<p>Location: {{ event.location_name }} - {{ event.calendareventaddressmodel }}</p>
|
||||||
{% if event.coordinator_email %}
|
{% if event.coordinator_email %}
|
||||||
<p>Coordinator: {{ event.coordinator_email }}</p>
|
<p>Coordinator: {{ event.coordinator_email }}</p>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Calendar | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/* Calendar Page Specific Styles */
|
/* Calendar Page Specific Styles */
|
||||||
.event-card {
|
.event-card {
|
||||||
@@ -23,7 +23,6 @@
|
|||||||
height: 180px;
|
height: 180px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
aspect-ratio: 16 / 9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs .nav-link {
|
.nav-tabs .nav-link {
|
||||||
@@ -63,29 +62,20 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Stonehedge community calendar — upcoming HOA events, gatherings, and past activities for Wheaton residents.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}Calendar | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Stonehedge community calendar — upcoming HOA events, gatherings, and past activities for Wheaton residents.{% endblock %}
|
|
||||||
{% block twitter_title %}Calendar | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Stonehedge community calendar — upcoming HOA events, gatherings, and past activities for Wheaton residents.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
<main class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Calendar Navigation -->
|
<!-- Calendar Navigation -->
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h1 class="text-success mb-3">Community Calendar</h1>
|
|
||||||
<ul class="nav nav-tabs" id="calendarTabs" role="tablist">
|
<ul class="nav nav-tabs" id="calendarTabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link active" id="upcoming-tab" data-bs-toggle="tab" data-bs-target="#upcoming" type="button" role="tab" aria-controls="upcoming" aria-selected="true">
|
<button class="nav-link active" id="upcoming-tab" data-bs-toggle="tab" data-bs-target="#upcoming" type="button" role="tab">
|
||||||
Upcoming Events
|
Upcoming Events
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="past-tab" data-bs-toggle="tab" data-bs-target="#past" type="button" role="tab" aria-controls="past" aria-selected="false">
|
<button class="nav-link" id="past-tab" data-bs-toggle="tab" data-bs-target="#past" type="button" role="tab">
|
||||||
Past Events
|
Past Events
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
@@ -115,9 +105,7 @@
|
|||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<p class="mb-1"><i class="bi bi-calendar-event text-success me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
<p class="mb-1"><i class="bi bi-calendar-event text-success me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
||||||
{% if event.time_range_display %}
|
<p class="mb-1"><i class="bi bi-clock text-success me-2"></i><strong>Time:</strong> 11:00 AM - 3:00 PM</p>
|
||||||
<p class="mb-1"><i class="bi bi-clock text-success me-2"></i><strong>Time:</strong> {{ event.time_range_display }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<p class="mb-1"><i class="bi bi-geo-alt text-success me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
<p class="mb-1"><i class="bi bi-geo-alt text-success me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
||||||
<p class="mb-1"><i class="bi bi-house text-success me-2"></i><strong>Address:</strong> </p>
|
<p class="mb-1"><i class="bi bi-house text-success me-2"></i><strong>Address:</strong> </p>
|
||||||
<p class="mb-1"><i class="bi bi-person text-success me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
<p class="mb-1"><i class="bi bi-person text-success me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
||||||
@@ -161,9 +149,7 @@
|
|||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<p class="mb-1"><i class="bi bi-calendar-event text-secondary me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
<p class="mb-1"><i class="bi bi-calendar-event text-secondary me-2"></i><strong>Date:</strong> {{ event.start_date }}</p>
|
||||||
{% if event.time_range_display %}
|
<p class="mb-1"><i class="bi bi-clock text-secondary me-2"></i><strong>Time:</strong> 9:00 AM - 12:00 PM</p>
|
||||||
<p class="mb-1"><i class="bi bi-clock text-secondary me-2"></i><strong>Time:</strong> {{ event.time_range_display }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<p class="mb-1"><i class="bi bi-geo-alt text-secondary me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
<p class="mb-1"><i class="bi bi-geo-alt text-secondary me-2"></i><strong>Location:</strong> {{ event.location_name }}</p>
|
||||||
<p class="mb-1"><i class="bi bi-house text-secondary me-2"></i><strong>Address:</strong> </p>
|
<p class="mb-1"><i class="bi bi-house text-secondary me-2"></i><strong>Address:</strong> </p>
|
||||||
<p class="mb-1"><i class="bi bi-person text-secondary me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
<p class="mb-1"><i class="bi bi-person text-secondary me-2"></i><strong>Coordinator:</strong> {{ event.coordinator_name }}</p>
|
||||||
@@ -186,7 +172,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Pay Dues | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/* Payment Page Specific Styles */
|
/* Payment Page Specific Styles */
|
||||||
.payment-option-card {
|
.payment-option-card {
|
||||||
@@ -50,23 +50,15 @@
|
|||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Pay annual Stonehedge HOA dues securely online via Stripe. Current annual dues are $30.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}Pay Dues | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Pay annual Stonehedge HOA dues securely online via Stripe. Current annual dues are $30.{% endblock %}
|
|
||||||
{% block twitter_title %}Pay Dues | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Pay annual Stonehedge HOA dues securely online via Stripe. Current annual dues are $30.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
<main class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
<!-- Payment Information Card -->
|
<!-- Payment Information Card -->
|
||||||
<div class="card shadow-sm mb-5">
|
<div class="card shadow-sm mb-5">
|
||||||
<div class="card-header bg-success text-white">
|
<div class="card-header bg-success text-white">
|
||||||
<h1 class="h3 mb-0">Payment Information</h1>
|
<h3 class="mb-0">Payment Information</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
@@ -118,7 +110,7 @@
|
|||||||
<h4 class="text-success">Credit/Debit Card</h4>
|
<h4 class="text-success">Credit/Debit Card</h4>
|
||||||
<p class="card-text">Pay securely with Visa, Mastercard, American Express, or Discover.</p>
|
<p class="card-text">Pay securely with Visa, Mastercard, American Express, or Discover.</p>
|
||||||
|
|
||||||
<button class="btn btn-success mt-3" id="submitBtn" type="button" aria-label="Pay annual dues with credit or debit card">Pay Dues</button>
|
<button class="btn btn-success mt-3" id="submitBtn">Pay Dues</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -192,7 +184,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
|
|||||||
@@ -2,18 +2,16 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Payment Cancelled | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Your Stonehedge HOA dues payment was cancelled.">
|
|
||||||
<meta name="robots" content="noindex, nofollow">
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
|
||||||
<div class="container">
|
|
||||||
<h1>Your payment cancelled.</h1>
|
|
||||||
</div>
|
<div class="mid-body">
|
||||||
</div>
|
<h1>Your payment cancelled.</h1>
|
||||||
{% endblock %}
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -2,18 +2,16 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Payment Successful | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Your Stonehedge HOA dues payment was successful.">
|
|
||||||
<meta name="robots" content="noindex, nofollow">
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
|
||||||
<div class="container">
|
|
||||||
<h1>Your payment succeeded.</h1>
|
|
||||||
</div>
|
<div class="mid-body">
|
||||||
</div>
|
<h1>Your payment succeeded.</h1>
|
||||||
{% endblock %}
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Home | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.hero-section {
|
.hero-section {
|
||||||
background: url({% static 'images/header.gif' %});
|
background: url({% static 'images/header.gif' %});
|
||||||
@@ -20,14 +20,6 @@
|
|||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Welcome to Stonehedge Community Homeowners Association in Wheaton, IL. Pay dues, join as a member, find events, and meet the HOA board.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}Home | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Welcome to Stonehedge Community Homeowners Association in Wheaton, IL. Pay dues, join as a member, find events, and meet the HOA board.{% endblock %}
|
|
||||||
{% block twitter_title %}Home | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Welcome to Stonehedge Community Homeowners Association in Wheaton, IL. Pay dues, join as a member, find events, and meet the HOA board.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Hero Section -->
|
<!-- Hero Section -->
|
||||||
<section id="home" class="py-5 bg-success bg-opacity-10">
|
<section id="home" class="py-5 bg-success bg-opacity-10">
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
# Stonehedge Community Homeowners Association (SCHA)
|
|
||||||
|
|
||||||
> Public website for the Stonehedge Community Homeowners Association in Wheaton, Illinois.
|
|
||||||
|
|
||||||
Stonehedge is a residential homeowners association serving Wheaton, IL. This site helps residents learn about the community, pay annual dues, join as members, view events, meet the board, and find useful local links.
|
|
||||||
|
|
||||||
## Primary pages
|
|
||||||
|
|
||||||
- [Home]({{ site_root }}): Community overview and quick links to dues, membership, events, and the board
|
|
||||||
- [About Us]({{ site_root }}about_us): Schools, community history, local shopping/dining, and nearby parks
|
|
||||||
- [Calendar]({{ site_root }}calendar): Upcoming and past community events
|
|
||||||
- [Pay Dues]({{ site_root }}dues): Annual dues payment via Stripe checkout ($30/year)
|
|
||||||
- [Join Today]({{ site_root }}membership_form): New member registration form (address, household contacts, committee interests)
|
|
||||||
- [SCHA Board]({{ site_root }}scha_board): Current volunteer board officers and contacts
|
|
||||||
- [Useful Links]({{ site_root }}useful_links): External resources for residents
|
|
||||||
|
|
||||||
## Machine-readable discovery
|
|
||||||
|
|
||||||
- Sitemap: {{ site_root }}sitemap.xml
|
|
||||||
- Robots: {{ site_root }}robots.txt
|
|
||||||
- This file: {{ site_root }}llms.txt
|
|
||||||
|
|
||||||
## Transactional flows
|
|
||||||
|
|
||||||
- Membership: HTML form POST to /membership_form (CSRF protected; includes reCAPTCHA)
|
|
||||||
- Dues payment: client creates Stripe Checkout session via /create-checkout-session/, then redirects to Stripe
|
|
||||||
|
|
||||||
## Notes for agents
|
|
||||||
|
|
||||||
- Prefer public navigation links in the primary navbar / footer
|
|
||||||
- Do not scrape or interact with /admin/ or member-only DEBUG routes
|
|
||||||
- Keep interactions within visible, labeled controls; payment completes on Stripe's hosted checkout
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Join Today | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
<style type="text/css">
|
<script type="text/css">
|
||||||
/* Membership Form Specific Styles */
|
/* Membership Form Specific Styles */
|
||||||
#membershipForm fieldset {
|
#membershipForm fieldset {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
@@ -60,26 +60,18 @@
|
|||||||
.modal-header .btn-close {
|
.modal-header .btn-close {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
</style>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Join Stonehedge Community Homeowners Association. Submit membership details, household contacts, and committee interests.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}Join Today | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Join Stonehedge Community Homeowners Association. Submit membership details, household contacts, and committee interests.{% endblock %}
|
|
||||||
{% block twitter_title %}Join Today | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Join Stonehedge Community Homeowners Association. Submit membership details, household contacts, and committee interests.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
<main class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
<div class="card-header bg-success text-white">
|
<div class="card-header bg-success text-white">
|
||||||
<h1 class="h4 mb-0">New Member Information</h1>
|
<h2 class="h4 mb-0">New Member Information</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form id="membershipForm" method="POST" action='{% url "membership_form2" %}' class="needs-validation" novalidate>
|
<form id="membershipForm" method="POST" action='{% url "membership_form2" %}' class="needs-validation" novalidate>
|
||||||
@@ -120,7 +112,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label for="zipCode" class="form-label">ZIP Code*</label>
|
<label for="zipCode" class="form-label">ZIP Code*</label>
|
||||||
<input type="text" class="form-control" id="zipCode" name="zipCode" value="60189" required>
|
<input type="text" class="form-control" id="zipCode" value="zipCode" value="60189" required>
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
Please provide your ZIP code.
|
Please provide your ZIP code.
|
||||||
</div>
|
</div>
|
||||||
@@ -205,77 +197,77 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="block_captain" name="block_captain">
|
<input class="form-check-input" type="checkbox" id="block_captain" for="block_captain" name="block_captain">
|
||||||
<label class="form-check-label" for="block_captain">
|
<label class="form-check-label" id="block_captain">
|
||||||
BlockCaptain
|
BlockCaptain
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="coordinator" name="coordinator">
|
<input class="form-check-input" type="checkbox" id="coordinator" for="coordinator" name="coordinator">
|
||||||
<label class="form-check-label" for="coordinator">
|
<label class="form-check-label" id="coordinator">
|
||||||
Coordinator
|
Coordinator
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="egg_hunt" name="egg_hunt">
|
<input class="form-check-input" type="checkbox" id="egg_hunt" for="egg_hunt" name="egg_hunt">
|
||||||
<label class="form-check-label" for="egg_hunt">
|
<label class="form-check-label" id="egg_hunt">
|
||||||
Easter Egg Hunt
|
Easter Egg Hunt
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="spring_garage_sale" name="spring_garage_sale">
|
<input class="form-check-input" type="checkbox" id="spring_garage_sale" for="spring_garage_sale" name="spring_garage_sale">
|
||||||
<label class="form-check-label" for="spring_garage_sale">
|
<label class="form-check-label" id="spring_garage_sale">
|
||||||
Spring Garage Sale
|
Spring Garage Sale
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="golf_outing" name="golf_outing">
|
<input class="form-check-input" type="checkbox" id="golf_outing" for="golf_outing" name="golf_outing">
|
||||||
<label class="form-check-label" for="golf_outing">
|
<label class="form-check-label" id="golf_outing">
|
||||||
Golf Outing
|
Golf Outing
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="ice_cream_social" name="ice_cream_social">
|
<input class="form-check-input" type="checkbox" id="ice_cream_social" for="ice_cream_social" name="ice_cream_social">
|
||||||
<label class="form-check-label" for="ice_cream_social">
|
<label class="form-check-label" id="ice_cream_social">
|
||||||
Ice Creame Social
|
Ice Creame Social
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="fall_garage_sale" name="fall_garage_sale">
|
<input class="form-check-input" type="checkbox" id="fall_garage_sale" for="fall_garage_sale" name="fall_garage_sale">
|
||||||
<label class="form-check-label" for="fall_garage_sale">
|
<label class="form-check-label" id="fall_garage_sale">
|
||||||
Fall Garage Sale
|
Fall Garage Sale
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="halloween_party" name="halloween_party">
|
<input class="form-check-input" type="checkbox" id="halloween_party" for="halloween_party" name="halloween_party">
|
||||||
<label class="form-check-label" for="halloween_party">
|
<label class="form-check-label" id="halloween_party">
|
||||||
Halloween Party
|
Halloween Party
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="santa_visit" name="santa_visit">
|
<input class="form-check-input" type="checkbox" id="santa_visit" for="santa_visit" name="santa_visit">
|
||||||
<label class="form-check-label" for="santa_visit">
|
<label class="form-check-label" id="santa_visit">
|
||||||
Santa Visits
|
Santa Visits
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="civic_affair" name="civic_affair">
|
<input class="form-check-input" type="checkbox" id="civic_affair" for="civic_affair" name="civic_affair">
|
||||||
<label class="form-check-label" for="civic_affair">
|
<label class="form-check-label" id="civic_affair">
|
||||||
Civic Affairs Journalist
|
Civic Affairs Journalist
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="phone_directory" name="phone_directory">
|
<input class="form-check-input" type="checkbox" id="phone_directory" for="phone_directory" name="phone_directory">
|
||||||
<label class="form-check-label" for="phone_directory">
|
<label class="form-check-label" id="phone_directory">
|
||||||
Annual Phone Director
|
Annual Phone Director
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<input class="form-check-input" type="checkbox" id="no_preference" name="no_preference">
|
<input class="form-check-input" type="checkbox" id="no_preference" for="no_preference" name="no_preference">
|
||||||
<label class="form-check-label" for="no_preference">
|
<label class="form-check-label" id="no_preference">
|
||||||
No Preference
|
No Preference
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -360,7 +352,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -2,22 +2,8 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Newsletters | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Stonehedge Community Homeowners Association newsletters and community updates for Wheaton residents.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}Newsletters | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Stonehedge Community Homeowners Association newsletters and community updates for Wheaton residents.{% endblock %}
|
|
||||||
{% block twitter_title %}Newsletters | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Stonehedge Community Homeowners Association newsletters and community updates for Wheaton residents.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
{% endblock %}
|
||||||
<div class="container">
|
|
||||||
<h1 class="text-success mb-3">Newsletters</h1>
|
|
||||||
<p class="lead">Community newsletters will appear here as they are published.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
User-agent: *
|
|
||||||
Allow: /
|
|
||||||
|
|
||||||
Disallow: /admin/
|
|
||||||
Disallow: /login/
|
|
||||||
Disallow: /signup/
|
|
||||||
Disallow: /dashboard/
|
|
||||||
Disallow: /directory/
|
|
||||||
Disallow: /posts/
|
|
||||||
Disallow: /posts_create/
|
|
||||||
Disallow: /profile/
|
|
||||||
Disallow: /password_reset/
|
|
||||||
Disallow: /set_password/
|
|
||||||
Disallow: /config/
|
|
||||||
Disallow: /create-checkout-session/
|
|
||||||
Disallow: /webhook/
|
|
||||||
|
|
||||||
Sitemap: {{ sitemap_url }}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>SCHA Board | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/* Board Page Specific Styles */
|
/* Board Page Specific Styles */
|
||||||
.card-header h4 {
|
.card-header h4 {
|
||||||
@@ -35,23 +35,15 @@
|
|||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Meet the volunteer Stonehedge Community Homeowners Association board officers serving Wheaton residents.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}SCHA Board | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Meet the volunteer Stonehedge Community Homeowners Association board officers serving Wheaton residents.{% endblock %}
|
|
||||||
{% block twitter_title %}SCHA Board | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Meet the volunteer Stonehedge Community Homeowners Association board officers serving Wheaton residents.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
<main class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Board Information -->
|
<!-- Board Information -->
|
||||||
<div class="row justify-content-center mb-5">
|
<div class="row justify-content-center mb-5">
|
||||||
<div class="col-lg-10">
|
<div class="col-lg-10">
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
<h1 class="h3 text-success mb-3">2025-2026 Stonehedge Community Homeowners Association Board</h1>
|
<h3 class="text-success mb-3">2025-2026 Stonehedge Community Homeowners Association Board</h3>
|
||||||
<p>The Stonehedge Community Homeowners Association is governed by a volunteer board of directors elected by the community members. Board members serve two-year terms and are responsible for overseeing the community's operations, finances, and enforcement of covenants.</p>
|
<p>The Stonehedge Community Homeowners Association is governed by a volunteer board of directors elected by the community members. Board members serve two-year terms and are responsible for overseeing the community's operations, finances, and enforcement of covenants.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,5 +98,5 @@
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
||||||
{% for entry in urls %}
|
|
||||||
<url>
|
|
||||||
<loc>{{ entry.loc }}</loc>
|
|
||||||
<changefreq>{{ entry.changefreq }}</changefreq>
|
|
||||||
<priority>{{ entry.priority }}</priority>
|
|
||||||
</url>
|
|
||||||
{% endfor %}
|
|
||||||
</urlset>
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block pagetitle %}
|
{% block pagetitle %}
|
||||||
<title>Useful Links | Stonehedge Community Homeowners Association</title>
|
<title>Stonehedge Community Homeowners Association</title>
|
||||||
<style type="text/css">
|
<script type="text/css">
|
||||||
/* Links Page Specific Styles */
|
/* Links Page Specific Styles */
|
||||||
.links-table th {
|
.links-table th {
|
||||||
background-color: var(--bs-success);
|
background-color: var(--bs-success);
|
||||||
@@ -41,25 +41,17 @@
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta_tags %}
|
|
||||||
<meta name="description" content="Helpful links for Stonehedge residents — city services, utilities, schools, and neighborhood resources.">
|
|
||||||
{% endblock %}
|
|
||||||
{% block og_title %}Useful Links | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block og_description %}Helpful links for Stonehedge residents — city services, utilities, schools, and neighborhood resources.{% endblock %}
|
|
||||||
{% block twitter_title %}Useful Links | Stonehedge Community Homeowners Association{% endblock %}
|
|
||||||
{% block twitter_description %}Helpful links for Stonehedge residents — city services, utilities, schools, and neighborhood resources.{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="py-5">
|
<main class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-lg-10">
|
<div class="col-lg-10">
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
<div class="card-header bg-success text-white">
|
<div class="card-header bg-success text-white">
|
||||||
<h1 class="h3 mb-0">Useful Links</h1>
|
<h3 class="mb-0">Useful Links</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
@@ -272,7 +264,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -89,49 +89,6 @@ class PublicPageTests(TestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertContains(response, "City of Wheaton")
|
self.assertContains(response, "City of Wheaton")
|
||||||
|
|
||||||
def test_public_pages_include_seo_metadata(self):
|
|
||||||
pages = [
|
|
||||||
("index2", "Home | Stonehedge"),
|
|
||||||
("about_us2", "About Us | Stonehedge"),
|
|
||||||
("calendar2", "Calendar | Stonehedge"),
|
|
||||||
("dues2", "Pay Dues | Stonehedge"),
|
|
||||||
("membership_form2", "Join Today | Stonehedge"),
|
|
||||||
("scha_board2", "SCHA Board | Stonehedge"),
|
|
||||||
("useful_links2", "Useful Links | Stonehedge"),
|
|
||||||
]
|
|
||||||
|
|
||||||
for name, title_fragment in pages:
|
|
||||||
with self.subTest(page=name):
|
|
||||||
response = self.client.get(reverse(name))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertContains(response, f"<title>{title_fragment}")
|
|
||||||
self.assertContains(response, 'name="description"')
|
|
||||||
self.assertContains(response, 'property="og:title"')
|
|
||||||
self.assertContains(response, 'rel="canonical"')
|
|
||||||
self.assertContains(response, 'id="main-content"')
|
|
||||||
self.assertContains(response, "Skip to main content")
|
|
||||||
|
|
||||||
def test_robots_txt(self):
|
|
||||||
response = self.client.get(reverse("robots_txt"))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
|
||||||
self.assertContains(response, "Sitemap:")
|
|
||||||
self.assertContains(response, "Disallow: /admin/")
|
|
||||||
|
|
||||||
def test_sitemap_xml(self):
|
|
||||||
response = self.client.get(reverse("sitemap_xml"))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertIn("xml", response["Content-Type"])
|
|
||||||
self.assertContains(response, reverse("index2"))
|
|
||||||
self.assertContains(response, reverse("dues2"))
|
|
||||||
|
|
||||||
def test_llms_txt(self):
|
|
||||||
response = self.client.get(reverse("llms_txt"))
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
|
||||||
self.assertContains(response, "Stonehedge Community Homeowners Association")
|
|
||||||
self.assertContains(response, reverse("membership_form2").lstrip("/"))
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
RECAPTCHA_PUBLIC_KEY="test-public-key",
|
RECAPTCHA_PUBLIC_KEY="test-public-key",
|
||||||
@@ -321,23 +278,6 @@ class CalendarEventTests(TestCase):
|
|||||||
self.assertFalse(undated.past_event())
|
self.assertFalse(undated.past_event())
|
||||||
self.assertFalse(undated.future_event())
|
self.assertFalse(undated.future_event())
|
||||||
|
|
||||||
def test_time_range_display(self):
|
|
||||||
event = CalendarEvent.objects.create(
|
|
||||||
event_name="Timed Event",
|
|
||||||
start_time=datetime.time(11, 0),
|
|
||||||
end_time=datetime.time(15, 0),
|
|
||||||
)
|
|
||||||
self.assertEqual(event.time_range_display(), "11:00 AM - 3:00 PM")
|
|
||||||
|
|
||||||
start_only = CalendarEvent.objects.create(
|
|
||||||
event_name="Start Only",
|
|
||||||
start_time=datetime.time(9, 30),
|
|
||||||
)
|
|
||||||
self.assertEqual(start_only.time_range_display(), "9:30 AM")
|
|
||||||
|
|
||||||
no_time = CalendarEvent.objects.create(event_name="No Time")
|
|
||||||
self.assertEqual(no_time.time_range_display(), "")
|
|
||||||
|
|
||||||
def test_calendar_page_splits_past_and_future(self):
|
def test_calendar_page_splits_past_and_future(self):
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
CalendarEvent.objects.create(
|
CalendarEvent.objects.create(
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ urlpatterns = authenticated_views + [
|
|||||||
path("membership_form", views.membership_form2, name="membership_form2"),
|
path("membership_form", views.membership_form2, name="membership_form2"),
|
||||||
path("scha_board", views.scha_board2, name="scha_board2"),
|
path("scha_board", views.scha_board2, name="scha_board2"),
|
||||||
path("useful_links", views.useful_links2, name="useful_links2"),
|
path("useful_links", views.useful_links2, name="useful_links2"),
|
||||||
path("robots.txt", views.robots_txt, name="robots_txt"),
|
|
||||||
path("sitemap.xml", views.sitemap_xml, name="sitemap_xml"),
|
|
||||||
path("llms.txt", views.llms_txt, name="llms_txt"),
|
|
||||||
# stripe specific urls below
|
# stripe specific urls below
|
||||||
path("config/", views.stripe_config),
|
path("config/", views.stripe_config),
|
||||||
path("create-checkout-session/", views.create_checkout_session),
|
path("create-checkout-session/", views.create_checkout_session),
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ from django.http.response import JsonResponse, HttpResponse
|
|||||||
from django.views.decorators.csrf import csrf_exempt # new
|
from django.views.decorators.csrf import csrf_exempt # new
|
||||||
from django.contrib.auth import logout, authenticate, login
|
from django.contrib.auth import logout, authenticate, login
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.urls import reverse
|
|
||||||
import stripe
|
import stripe
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -123,55 +122,6 @@ def useful_links(request):
|
|||||||
return render(request, "schasite/useful_links.html", {"links": useful_links})
|
return render(request, "schasite/useful_links.html", {"links": useful_links})
|
||||||
|
|
||||||
|
|
||||||
PUBLIC_SITEMAP_ROUTES = (
|
|
||||||
("index2", "weekly", "1.0"),
|
|
||||||
("about_us2", "monthly", "0.8"),
|
|
||||||
("calendar2", "weekly", "0.8"),
|
|
||||||
("dues2", "monthly", "0.9"),
|
|
||||||
("membership_form2", "monthly", "0.9"),
|
|
||||||
("scha_board2", "monthly", "0.7"),
|
|
||||||
("useful_links2", "monthly", "0.6"),
|
|
||||||
("newsletters2", "monthly", "0.5"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def robots_txt(request):
|
|
||||||
sitemap_url = request.build_absolute_uri(reverse("sitemap_xml"))
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"schasite/robots.txt",
|
|
||||||
{"sitemap_url": sitemap_url},
|
|
||||||
content_type="text/plain",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def sitemap_xml(request):
|
|
||||||
urls = [
|
|
||||||
{
|
|
||||||
"loc": request.build_absolute_uri(reverse(name)),
|
|
||||||
"changefreq": changefreq,
|
|
||||||
"priority": priority,
|
|
||||||
}
|
|
||||||
for name, changefreq, priority in PUBLIC_SITEMAP_ROUTES
|
|
||||||
]
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"schasite/sitemap.xml",
|
|
||||||
{"urls": urls},
|
|
||||||
content_type="application/xml",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def llms_txt(request):
|
|
||||||
site_root = request.build_absolute_uri("/")
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"schasite/llms.txt",
|
|
||||||
{"site_root": site_root},
|
|
||||||
content_type="text/plain; charset=utf-8",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def index2(request):
|
def index2(request):
|
||||||
return render(request, "schasite/index2.html", {})
|
return render(request, "schasite/index2.html", {})
|
||||||
|
|
||||||
|
|||||||
@@ -101,16 +101,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django"
|
name = "django"
|
||||||
version = "6.0.7"
|
version = "5.2.16"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "asgiref" },
|
{ name = "asgiref" },
|
||||||
{ name = "sqlparse" },
|
{ name = "sqlparse" },
|
||||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/89/55/664f24ff81c9ea19cb7dfc851afeae1f3c2390c7aee01d4ded68b5c1580d/django-6.0.7.tar.gz", hash = "sha256:2998503fc083124fb58037084bfa00de323c7c743f05f1b4284e77bff0ab8890", size = 10921299, upload-time = "2026-07-07T13:51:26.485Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/a9/26/889449d521ae508b26de715954faecd8bcf3f740affb81b2d146a83b42a5/django-5.2.16.tar.gz", hash = "sha256:59ea02020c3136fce14bef0bbece21a10a4febef5eed1c51c22ae468efa22200", size = 10890894, upload-time = "2026-07-07T13:52:17.005Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ba/ec/1ce5334b6a2c52ce619c23a0be8d366a57a0e080ebb2d88266e5c849157c/django-6.0.7-py3-none-any.whl", hash = "sha256:a037427c2288443a8c02a1b02295a31c239663aa682bc50b1976afb7cf6a769e", size = 8373344, upload-time = "2026-07-07T13:51:20.007Z" },
|
{ url = "https://files.pythonhosted.org/packages/4e/13/1e5e3e4c15dcecb04281b3cb2a46a4670e1cef131068e202f6040df19224/django-5.2.16-py3-none-any.whl", hash = "sha256:04f354bf9d807a86ad1a8392fe3808d362358a8eafc322848e0e43e59b24371d", size = 8311943, upload-time = "2026-07-07T13:52:11.223Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -366,7 +366,7 @@ dev = [
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "django", specifier = ">=6.0,<7" },
|
{ name = "django", specifier = ">=5.2,<6" },
|
||||||
{ name = "django-phonenumber-field", specifier = ">=8.1.0" },
|
{ name = "django-phonenumber-field", specifier = ">=8.1.0" },
|
||||||
{ name = "django-recaptcha", specifier = ">=4.1.0" },
|
{ name = "django-recaptcha", specifier = ">=4.1.0" },
|
||||||
{ name = "gunicorn", specifier = ">=23.0.0" },
|
{ name = "gunicorn", specifier = ">=23.0.0" },
|
||||||
|
|||||||
Reference in New Issue
Block a user