Closes #32. Keep an event upcoming until its end date (and end time, when set) has passed, and render the Past tab from past events.
243 lines
9.5 KiB
Python
243 lines
9.5 KiB
Python
from django.db import models
|
|
from phonenumber_field.modelfields import PhoneNumberField
|
|
import datetime
|
|
from django.utils import timezone
|
|
from django.conf import settings
|
|
|
|
class TimeInfoBase(models.Model):
|
|
|
|
created = models.DateTimeField(default=timezone.now)
|
|
last_modified = models.DateTimeField(default=timezone.now)
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
def save(self, **kwargs):
|
|
if not kwargs.pop("skip_last_modified", False) and not hasattr(self, "skip_last_modified"):
|
|
self.last_modified = timezone.now()
|
|
if kwargs.get("update_fields") is not None:
|
|
kwargs["update_fields"] = list({*kwargs["update_fields"], "last_modified"})
|
|
|
|
super().save(**kwargs)
|
|
|
|
# Create your models here.
|
|
class UsefulLinks(TimeInfoBase):
|
|
name = models.CharField(max_length=256)
|
|
url = models.CharField(max_length=256)
|
|
|
|
|
|
class Membership(TimeInfoBase):
|
|
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(TimeInfoBase):
|
|
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(TimeInfoBase):
|
|
event_name = models.CharField(max_length=256)
|
|
start_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)
|
|
coordinator_email = models.EmailField(max_length=256, blank=True, null=True)
|
|
event_link_name = models.CharField(max_length=64, blank=True, null=True)
|
|
event_url = models.URLField(max_length=256, blank=True, null=True)
|
|
#description= models.CharField(max_length=1024, default="")
|
|
|
|
def has_date(self):
|
|
return not self.start_date is None
|
|
|
|
def _has_ended(self, now=None):
|
|
"""True once the event is over. In-progress multi-day events stay open
|
|
through end_date, and through end_time on that date when one is set.
|
|
"""
|
|
if not self.has_date():
|
|
return None
|
|
if now is None:
|
|
now = datetime.datetime.now()
|
|
|
|
end_date = self.end_date or self.start_date
|
|
if self.end_time:
|
|
return now >= datetime.datetime.combine(end_date, self.end_time)
|
|
return now.date() > end_date
|
|
|
|
def past_event(self):
|
|
ended = self._has_ended()
|
|
if ended is None:
|
|
return False
|
|
return ended
|
|
|
|
def future_event(self):
|
|
"""Upcoming or currently in progress."""
|
|
ended = self._has_ended()
|
|
if ended is None:
|
|
return False
|
|
return not ended
|
|
|
|
def no_date(self):
|
|
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):
|
|
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(TimeInfoBase):
|
|
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(TimeInfoBase):
|
|
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(TimeInfoBase):
|
|
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(TimeInfoBase):
|
|
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
|
|
)
|
|
|
|
|
|
class SCHAOfficer(TimeInfoBase):
|
|
name = models.CharField(max_length=255)
|
|
position = models.CharField(max_length=255)
|
|
email = models.EmailField(max_length=255)
|
|
|
|
### NOT USED YET ###
|
|
|
|
class CommunitySchools(TimeInfoBase):
|
|
name = models.CharField(max_length=255)
|
|
name_school_url = models.URLField(max_length=256)
|
|
rating_url = models.URLField(max_length=256)
|
|
rating = models.DecimalField(max_digits=5, decimal_places=2)
|
|
distance = models.DecimalField(max_digits=3, decimal_places=1)
|
|
principal = models.CharField(max_length=255)
|
|
grades = models.CharField(max_length=255)
|
|
|
|
class CommunityShoppingAndDining(TimeInfoBase):
|
|
name = models.CharField(max_length=255)
|
|
distance = models.DecimalField(max_digits=3, decimal_places=1)
|
|
description = models.CharField(max_length=1024)
|
|
|
|
class CommunityParks(TimeInfoBase):
|
|
name = models.CharField(max_length=255)
|
|
distance = models.DecimalField(max_digits=3, decimal_places=1)
|
|
description = models.CharField(max_length=1024)
|
|
|
|
### Member only models
|
|
|
|
class CommunityMember(TimeInfoBase):
|
|
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
|
membership_person = models.OneToOneField(MembershipPerson, on_delete=models.CASCADE)
|
|
|
|
|
|
class CommunityPost(TimeInfoBase):
|
|
title = models.CharField(max_length=255)
|
|
category = models.CharField(max_length=255)
|
|
content = models.CharField(max_length=1024*8)
|
|
likes = models.IntegerField(default=0)
|
|
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE, blank=True, null=True)
|
|
|
|
class CommunityPostReports(TimeInfoBase):
|
|
# for anyone who reports a post
|
|
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
|
reporter = models.OneToOneField(CommunityMember, on_delete=models.CASCADE, blank=True, null=True)
|
|
|
|
class CommunityPostLikes(TimeInfoBase):
|
|
# for anyone who likes a post
|
|
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
|
reporter = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
|
|
|
|
class CommunityComment(TimeInfoBase):
|
|
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
|
|
content = models.CharField(max_length=1024*8)
|
|
likes = models.IntegerField(default=0)
|
|
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE, blank=True, null=True) |