Skip to content

Commit

Permalink
refactored email system
Browse files Browse the repository at this point in the history
  • Loading branch information
jabelone committed Sep 21, 2023
1 parent 4cbe0cd commit d43128d
Show file tree
Hide file tree
Showing 9 changed files with 521 additions and 333 deletions.
11 changes: 5 additions & 6 deletions memberportal/api_access/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@

logger = logging.getLogger("app")

from django.db.models.signals import pre_save
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib import auth
from access.models import Doors
from access.models import AccessControlledDevice, Doors
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

User = auth.get_user_model()


@receiver(pre_save, sender=Doors)
def save_or_create_door(sender, instance, **kwargs):
@receiver(post_save, sender=AccessControlledDevice)
def save_or_create_access_controlled_device(sender, instance, created, **kwargs):
# disable the handler during fixture loading
if kwargs["raw"]:
return

created = instance.pk is None
door_all_members_changed = False
door_maintenance_lockout_changed = False
door = Doors.objects.get(pk=instance.id)
door = AccessControlledDevice.objects.get(pk=instance.id)

# if we didn't just create the door check if it's properties have changed
if not created:
Expand Down
8 changes: 5 additions & 3 deletions memberportal/api_admin_tools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .models import MemberTier, PaymentPlan
from memberbucks.models import MemberBucks
from constance import config
from services.emails import send_single_email
from services.emails import send_email_to_admin
import json
import stripe
from sentry_sdk import capture_message
Expand Down Expand Up @@ -104,8 +104,10 @@ def post(self, request, member_id):
user.profile.save()

subject = f"{user.profile.get_full_name()} just got turned into a member!"
send_single_email(
request.user, config.EMAIL_ADMIN, subject, subject, subject
send_email_to_admin(
subject=subject,
template_vars={"title": subject, "message": subject},
user=request.user,
)

if email:
Expand Down
91 changes: 39 additions & 52 deletions memberportal/api_billing/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,6 @@ def post(self, request):

try:
request.user.email_notification(
subject,
subject,
subject,
"Don't worry, your card details are stored safe "
"with Stripe and are not on our servers. You "
Expand Down Expand Up @@ -423,40 +421,28 @@ def post(self, request):
return Response({"success": False, "score": 0, "error": str(e)})


def send_submitted_application_emails(member):
subject = "Your membership application has been submitted"
title = subject
message = "Thanks for submitting your membership application! Your membership application has been submitted and you are now a 'member applicant'. Your membership will be officially accepted after 7 days, but we have granted site access immediately. You will receive an email confirming that your access card has been enabled. If for some reason your membership is rejected within this period, you will receive an email with further information."
member.user.email_notification(subject, title, "", message)

subject = f"A new person just became a member applicant: {member.get_full_name()}"
title = subject
message = f"{member.get_full_name()} just completed all steps required to sign up and is now a member applicant. Their site access has been enabled and membership will automatically be accepted within 7 days without objection from the executive."
send_email_to_admin(subject, title, message, reply_to=member.user.email)


class CompleteSignup(StripeAPIView):
"""
post: completes the member's signup if they have completed all requirements and enables access
"""

def post(self, request):
member = request.user.profile
signupCheck = member.can_signup()
member_profile = request.user.profile
signupCheck = member_profile.can_signup()

if signupCheck["success"]:
member.activate()
send_submitted_application_emails(member)
member_profile.activate()

# give default door access
for door in Doors.objects.filter(all_members=True):
member.doors.add(door)
member_profile.doors.add(door)

# give default interlock access
for interlock in Interlock.objects.filter(all_members=True):
member.interlocks.add(interlock)
member_profile.interlocks.add(interlock)

member.user.email_welcome()
member_profile.user.email_membership_application()
member_profile.user.email_welcome()

return Response({"success": True})

Expand Down Expand Up @@ -584,15 +570,15 @@ def post(self, request):

data = data["object"]
try:
member = Profile.objects.get(stripe_customer_id=data["customer"])
member_profile = Profile.objects.get(stripe_customer_id=data["customer"])

except Profile.DoesNotExist as e:
capture_exception(e)
return Response()

# Just in case the linked Stripe account also processes other payments we should just ignore a non existent
# customer.
if not member:
if not member_profile:
return Response()

if event_type == "invoice.paid":
Expand All @@ -601,87 +587,88 @@ def post(self, request):
# If they aren't an active member, are allowed to signup, and have paid the invoice
# then lets activate their account (this could be a new OR returning member)
if (
member.state != "active"
and member.can_signup()["success"]
member_profile.state != "active"
and member_profile.can_signup()["success"]
and invoice_status == "paid"
):
subject = "Your payment was successful."
title = subject
message = (
"Thanks for making a membership payment using our online payment system. "
"You've already met all of the requirements for activating your site access. Please check "
"for another email message confirming this was successful."
)
member.user.email_notification(subject, title, "", message)
member_profile.user.email_notification(subject, message)

# set the subscription status to active
member.subscription_status = "active"
member.save()
member_profile.subscription_status = "active"
member_profile.save()

# activate their access card
member.activate()
member.user.email_enable_member()
member_profile.activate()
member_profile.user.email_enable_member()

# If they aren't an active member, are NOT allowed to signup, and have paid the invoice
# then we need to let them know and mark the subscription as active
# (this could be a new OR returning member that's been too long since induction etc.)
elif member.state != "active" and invoice_status == "paid":
elif member_profile.state != "active" and invoice_status == "paid":
subject = "Your payment was successful."
title = subject
message = (
"Thanks for making a membership payment using our online payment system. "
"You haven't yet met all of the requirements for activating your site access. Once this "
"happens, you'll receive an email confirmation that your access card was activated. "
"If you are unsure how to proceed, or this email is unexpected, please contact us."
)
member.user.email_notification(subject, title, "", message)
member_profile.user.email_notification(subject, message)

member.subscription_status = "active"
member.save()
member_profile.subscription_status = "active"
member_profile.save()

# if this is a returning member then send the exec an email (new members have
# already had this sent)
if member.state != "noob":
send_submitted_application_emails(member)
if member_profile.state != "noob":
member_profile.user.email_membership_application()

# in all other instances, we don't care about a paid invoice and can ignore it

if event_type == "invoice.payment_failed":
subject = "Your membership payment failed"
title = subject
preheader = ""
message = (
"Hi there, we tried to collect your membership payment via our online payment system but "
"weren't successful. Please update your billing information via the member portal or contact "
"us to resolve this issue. We'll try again, but if we're unable to collect your payment, your "
"membership may be cancelled."
)

member.user.email_notification(subject, title, preheader, message)
member_profile.user.email_notification(subject, message)

if event_type == "customer.subscription.deleted":
# the subscription was deleted, so deactivate the member
subject = "Your membership has been cancelled"
title = subject
preheader = ""
message = (
"You will receive another email shortly confirming that your access has been deactivated. Your "
"membership was cancelled because we couldn't collect your payment, or you chose not to renew it."
)

member.user.email_notification(subject, title, preheader, message)
member.deactivate()
member.membership_plan = None
member.stripe_subscription_id = None
member.subscription_status = "inactive"
member.save()
member_profile.user.email_notification(subject, message)
member_profile.deactivate()
member_profile.membership_plan = None
member_profile.stripe_subscription_id = None
member_profile.subscription_status = "inactive"
member_profile.save()

subject = f"The membership for {member.get_full_name()} was just cancelled"
subject = f"The membership for {member_profile.get_full_name()} was just cancelled"
title = subject
message = (
f"The Stripe subscription for {member.get_full_name()} ended, so their membership has "
f"The Stripe subscription for {member_profile.get_full_name()} ended, so their membership has "
f"been cancelled. Their site access has been turned off."
)
send_email_to_admin(subject, title, message, reply_to=member.user.email)
template_vars = {"title": title, "message": message}

send_email_to_admin(
subject,
template_vars=template_vars,
reply_to=member_profile.user.email,
user=member_profile.user,
)

return Response()
19 changes: 8 additions & 11 deletions memberportal/api_general/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ def post(self, request):
new_token.user.email_link(
"Action Required: Verify Email",
"Verify Email",
"Verify Email",
"Please verify your email address to activate your account.",
url,
"Verify Now",
Expand Down Expand Up @@ -673,7 +672,6 @@ def post(self, request):
verification_token.user.email_link(
"Action Required: Verify Email",
"Verify Email",
"Verify Email",
"Please verify your email address to activate your account.",
url,
"Verify Now",
Expand All @@ -682,18 +680,18 @@ def post(self, request):
profile.email_profile_to(config.EMAIL_ADMIN)

if not config.ENABLE_STRIPE_MEMBERSHIP_PAYMENTS:
new_user.email_link(
f"Action Required: {config.SITE_OWNER} New Member Signup",
"Next Step: Register for an Induction",
"Important. Please read this email for details on how to "
"register for an induction.",
subject = f"Action Required: {config.SITE_OWNER} New Member Signup"
title = "Next Step: Register for an Induction"
message = (
f"Hi {profile.first_name}, thanks for signing up! The next step to becoming a fully "
"fledged member is to book in for an induction. During this "
"induction we will go over the basic safety and operational "
f"aspects of {config.SITE_OWNER}. To book in, click the link below.",
f"{config.INDUCTION_URL}",
"Register for Induction",
f"aspects of {config.SITE_OWNER}. To book in, click the link below."
)
link = config.INDUCTION_URL
btn_text = "Register for Induction"

new_user.email_link(subject, title, message, link, btn_text)

try:
if config.MAILCHIMP_API_KEY:
Expand Down Expand Up @@ -778,7 +776,6 @@ def post(self, request, verify_token):
new_token.user.email_link(
"Action Required: Verify Email",
"Verify Email",
"Verify Email",
"Please verify your email address to activate your account.",
url,
"Verify Now",
Expand Down
31 changes: 27 additions & 4 deletions memberportal/api_meeting/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,23 @@ def post(self, request):
f"{request.user.profile.get_full_name()} just assigned you as a proxy"
)
message = f"{request.user.profile.get_full_name()} just assigned you as a proxy for the {meeting.get_type()} meeting on {localtime(meeting.date)}."
send_single_email(request.user, proxy_user.email, subject, subject, message)
send_single_email(
to_email=proxy_user.email,
subject=subject,
template_vars={
"title": subject,
"message": message,
},
user=request.user,
)

subject = f"{proxy_user.profile.get_full_name()} is confirmed as your proxy for the {meeting.get_type()} meeting"
message = f"{proxy_user.profile.get_full_name()} is confirmed as your proxy for the {meeting.get_type()} meeting on {localtime(meeting.date)}. You can manage this proxy from the member portal."
send_single_email(
request.user, request.user.email, subject, subject, message
to_email=request.user.email,
subject=subject,
template_vars={"title": subject, "message": message},
user=request.user,
)

return Response({"success": True})
Expand All @@ -154,13 +165,25 @@ def delete(self, request, proxy_id):
)
message = f"{request.user.profile.get_full_name()} just removed you as a proxy for the {proxy.meeting.get_type()} meeting on {localtime(proxy.meeting.date)}."
send_single_email(
request.user, proxy.proxy_user.email, subject, subject, message
to_email=proxy.proxy_user.email,
subject=subject,
template_vars={
"title": subject,
"message": message,
},
user=request.user,
)

subject = f"{proxy.proxy_user.profile.get_full_name()} is no longer your proxy for the {proxy.meeting.get_type()} meeting"
message = f"{proxy.proxy_user.profile.get_full_name()} is no longer your proxy for the {proxy.meeting.get_type()} meeting on {localtime(proxy.meeting.date)}. You can manage this proxy from the member portal."
send_single_email(
request.user, request.user.email, subject, subject, message
to_email=request.user.email,
subject=subject,
template_vars={
"title": subject,
"message": message,
},
user=request.user,
)
return Response()
else:
Expand Down
21 changes: 10 additions & 11 deletions memberportal/api_member_tools/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from profile.models import User, Profile
from api_meeting.models import Meeting
from constance import config
from services.emails import send_single_email
from services.emails import send_email_to_admin
from random import shuffle
import requests
from django.utils import timezone
Expand Down Expand Up @@ -147,16 +147,15 @@ def post(self, request):

# if Trello isn't configured, use email instead
else:
subject = (
f"{request.user.profile.get_full_name()} submitted an issue ({title})"
)

if send_single_email(
request.user,
config.EMAIL_ADMIN,
subject,
subject,
description,
subject = f"{request.user.profile.get_full_name()} submitted an issue about {title}"

if send_email_to_admin(
subject=subject,
template_vars={
"title": subject,
"message": description,
},
user=request.user,
reply_to=request.user.email,
):
return Response(
Expand Down
Loading

0 comments on commit d43128d

Please sign in to comment.