Skip to content

Commit

Permalink
Merge branch 'main' into migration-to-python3
Browse files Browse the repository at this point in the history
  • Loading branch information
milescalabresi committed May 16, 2024
2 parents 7c56b64 + b04ffe2 commit d03eab5
Show file tree
Hide file tree
Showing 17 changed files with 270 additions and 59 deletions.
2 changes: 1 addition & 1 deletion esp/esp/dbmail/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def send_mail(subject, message, from_email, recipient_list, fail_silently=False,
from_email = from_email.strip()
# the from_email must match one of our DMARC domains/subdomains
# or the email may be rejected by email clients
if not re.match(r"(^.+@%s>?$)|(^.+@(\w+\.)?learningu\.org>?$)" % settings.SITE_INFO[1].replace(".", "\."), from_email):
if not re.match(r'(^.+@{0}$)|(^.+<.+@{0}>$)|(^.+@(\w+\.)?learningu\.org$)|(^.+<.+@(\w+\.)?learningu\.org>$)'.format(settings.SITE_INFO[1].replace('.', '\.')), from_email):
raise ESPError("Invalid 'From' email address (" + from_email + "). The 'From' email address must " +
"end in @" + settings.SITE_INFO[1] + " (your website), " +
"@learningu.org, or a valid subdomain of learningu.org " +
Expand Down
18 changes: 11 additions & 7 deletions esp/esp/program/controllers/confirmation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

from __future__ import absolute_import
__author__ = "Individual contributors (see AUTHORS file)"
__date__ = "$DATE$"
__rev__ = "$REV$"
Expand Down Expand Up @@ -37,13 +36,14 @@
from esp.program.models import Program, ClassSection, ClassSubject
from esp.users.models import ESPUser, Record, RecordType
from esp.program.modules.module_ext import DBReceipt
from esp.program.modules.forms.admincore import get_template_source

from django.template import Template, Context
from django.template.loader import select_template
from esp.dbmail.models import send_mail

class ConfirmationEmailController(object):
def send_confirmation_email(self, user, program, repeat=False, override=False):
def send_confirmation_email(self, user, program, repeat=False, override=False, context = {}):
options = program.studentclassregmoduleinfo
## Get or create a userbit indicating whether or not email's been sent.
try:
Expand All @@ -52,12 +52,16 @@ def send_confirmation_email(self, user, program, repeat=False, override=False):
except Exception:
created = False
if (created or repeat) and (options.send_confirmation or override):
context['user'] = user
context['program'] = program
receipt = select_template(['program/confemails/%s_custom_receipt.html' %(program.id), 'program/confemails/default.html'])
# render the custom pretext first
try:
receipt_template = Template(DBReceipt.objects.get(program=program, action='confirmemail').receipt)
receipt_text = receipt_template.render(Context({'user': user, 'program': program}))
except:
receipt_template = select_template(['program/confemails/%s_confemail.txt' %(program.id), 'program/confemails/default.txt'])
receipt_text = receipt_template.render({'user': user, 'program': program})
pretext = DBReceipt.objects.get(program=program, action='confirmemail').receipt
except DBReceipt.DoesNotExist:
pretext = get_template_source(['program/confemails/%s_custom_pretext.html' %(program.id), 'program/confemails/default_pretext.html'])
context['pretext'] = Template(pretext).render( Context(context, autoescape=False) )
receipt_text = receipt.render( context )
send_mail("Thank you for registering for %s!" %(program.niceName()), \
receipt_text, \
(ESPUser.email_sendto_address(program.director_email, program.niceName() + " Directors")), \
Expand Down
4 changes: 2 additions & 2 deletions esp/esp/program/migrations/0027_auto_20240220_2124.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
def replace_director_emails(apps, schema_editor):
Program = apps.get_model('program', 'Program')
for prog in Program.objects.all():
if not re.match(r"(^.+@%s$)|(^.+@(\w+\.)*learningu\.org$)" % settings.SITE_INFO[1].replace(".", "\."), prog.director_email):
if not re.match(r'(^.+@{0}$)|(^.+@(\w+\.)?learningu\.org$)'.format(settings.SITE_INFO[1].replace('.', '\.')), prog.director_email):
prog.director_email = 'info@' + settings.SITE_INFO[1]
prog.save()

Expand All @@ -35,7 +35,7 @@ class Migration(migrations.Migration):
help_text='The director email address must end in @' + settings.SITE_INFO[1] +
' (your website), @learningu.org, or a valid subdomain of learningu.org (i.e., @subdomain.learningu.org). The default is <b>info@' + settings.SITE_INFO[1] +
'</b>, which redirects to the "default" email address from your site\'s settings by default. You can create and manage your email redirects <a href="/manage/redirects/">here</a>.',
validators=[validators.RegexValidator(r'(^.+@%s$)|(^.+@(\w+\.)?learningu\.org$)' % settings.SITE_INFO[1].replace('.', '\.'))]),
validators=[validators.RegexValidator(r'(^.+@{0}$)|(^.+<.+@{0}>$)|(^.+@(\w+\.)?learningu\.org$)|(^.+<.+@(\w+\.)?learningu\.org>$)'.format(settings.SITE_INFO[1].replace('.', '\.')))]),
),
# This will run backwards, but won't do anything
migrations.RunPython(replace_director_emails, lambda a, s: None),
Expand Down
2 changes: 1 addition & 1 deletion esp/esp/program/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class Program(models.Model, CustomFormsLinkModel):
grade_max = models.IntegerField()
# director contact email address used for from field and display
director_email = models.EmailField(default='info@' + settings.SITE_INFO[1], max_length=75,
validators=[validators.RegexValidator(r'(^.+@%s$)|(^.+@(\w+\.)?learningu\.org$)' % settings.SITE_INFO[1].replace('.', '\.'))],
validators=[validators.RegexValidator(r'(^.+@{0}$)|(^.+@(\w+\.)?learningu\.org$)'.format(settings.SITE_INFO[1].replace('.', '\.')))],
help_text=mark_safe('The director email address must end in @' + settings.SITE_INFO[1] + ' (your website), ' +
'@learningu.org, or a valid subdomain of learningu.org (i.e., @subdomain.learningu.org). ' +
'The default is <b>info@' + settings.SITE_INFO[1] + '</b>, which redirects to the "default" ' +
Expand Down
35 changes: 18 additions & 17 deletions esp/esp/program/modules/forms/admincore.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import absolute_import
from decimal import Decimal
from django import forms
from django.conf import settings
Expand All @@ -19,7 +18,7 @@
from esp.utils.models import TemplateOverride

def get_rt_choices():
choices = [("All", "All")]
choices = [("All","All")]
for rt in RegistrationType.objects.all().order_by('name'):
if rt.displayName:
choices.append((rt.name, '%s (displayed as "%s")' % (rt.name, rt.displayName)))
Expand Down Expand Up @@ -91,16 +90,16 @@ def save(self):
class Meta:
fieldsets = [
('Program Title', {'fields': ['term', 'term_friendly'] }),
('Program Constraints', {'fields':['grade_min', 'grade_max', 'program_size_max', 'program_allow_waitlist']}),
('About Program Creator', {'fields':['director_email', 'director_cc_email', 'director_confidential_email']}),
('Financial Details', {'fields':['base_cost', 'sibling_discount']}),
('Program Internal Details', {'fields':['program_type', 'program_modules', 'program_module_questions', 'class_categories', 'flag_types']}),
('Program Constraints', {'fields':['grade_min','grade_max','program_size_max','program_allow_waitlist']}),
('About Program Creator',{'fields':['director_email', 'director_cc_email', 'director_confidential_email']}),
('Financial Details' ,{'fields':['base_cost','sibling_discount']}),
('Program Internal Details' ,{'fields':['program_type','program_modules','program_module_questions','class_categories','flag_types']}),
]# Here you can also add description for each fieldset.
widgets = {
'program_modules': forms.SelectMultiple(attrs={'class': 'hidden-field'}),
}
model = Program
ProgramSettingsForm.base_fields['director_email'].widget = forms.EmailInput(attrs={'pattern': r'(^.+@%s$)|(^.+@(\w+\.)?learningu\.org$)' % settings.SITE_INFO[1].replace('.', '\.')})
ProgramSettingsForm.base_fields['director_email'].widget = forms.EmailInput(attrs={'pattern': r'(^.+@{0}$)|(^.+@(\w+\.)?learningu\.org$)'.format(settings.SITE_INFO[1].replace('.', '\.'))})

class TeacherRegSettingsForm(BetterModelForm):
""" Form for changing teacher class registration settings. """
Expand Down Expand Up @@ -128,7 +127,7 @@ class Meta:
('Priority Registration Settings', {'fields': ['priority_limit']}), # use_priority is not included here to prevent confusion; to my knowledge, only HSSP uses this setting - WG
('Enrollment Settings', {'fields': ['register_from_catalog', 'visible_enrollments', 'visible_meeting_times', 'show_emailcodes']}), # use_grade_range_exceptions is excluded until there is an interface for it - WG 5/25/23
('Button Settings', {'fields': ['confirm_button_text', 'view_button_text', 'cancel_button_text', 'temporarily_full_text', 'cancel_button_dereg', 'send_confirmation']}),
('Visual Options', {'fields': ['progress_mode', 'force_show_required_modules']}),
('Visual Options', {'fields': ['progress_mode','force_show_required_modules']}),
]# Here you can also add description for each fieldset.
model = StudentClassRegModuleInfo

Expand All @@ -141,14 +140,16 @@ def get_template_source(template_list):

class ReceiptsForm(BetterForm):
confirm = forms.CharField(widget=forms.Textarea(attrs={'class': 'fullwidth'}),
help_text = "This text is shown on the website when a student clicks the 'confirm registration' button (HTML is supported).\
If no text is supplied, the default text will be used. The text is then followed by the student's information,\
the program information, the student's purchased items, and the student's schedule.",
help_text = mark_safe("This text is <b>shown on the website</b> when a student clicks the 'confirm registration' button (HTML is supported).\
If no text is supplied, the default text will be used. The text is then followed by the student's information,\
the program information, the student's purchased items, and the student's schedule."),
required = False)
confirmemail = forms.CharField(widget=forms.Textarea(attrs={'class': 'fullwidth'}),
help_text = "This receipt is sent via email when a student clicks the 'confirm registration' button.\
If no text is supplied, the default text will be used.",
required = False)
help_text = mark_safe("This text is <b>sent via email</b> when a student clicks the 'confirm registration' button.\
If no text is supplied, the default text will be used. The text is then followed by the student's information,\
the program information, the student's purchased items, and the student's schedule. This email can be disabled\
by deactivating the 'Send confirmation' option in the 'Student Registration Settings' above."),
required = False)
cancel = forms.CharField(widget=forms.Textarea(attrs={'class': 'fullwidth'}),
help_text = "This receipt is shown on the website when a student clicks the 'cancel registration' button.\
If no text is supplied, the student will be redirected to the main student registration page instead.",
Expand All @@ -164,7 +165,7 @@ def __init__(self, *args, **kwargs):
elif action == "confirm":
receipt_text = get_template_source(['program/receipts/%s_custom_pretext.html' %(self.program.id), 'program/receipts/default_pretext.html'])
elif action == "confirmemail":
receipt_text = get_template_source(['program/confemails/%s_confemail.txt' %(self.program.id), 'program/confemails/default.txt'])
receipt_text = get_template_source(['program/confemails/%s_confemail_pretext.html' %(self.program.id),'program/confemails/default_pretext.html'])
else:
receipt_text = ""
self.fields[action].initial = receipt_text.encode('UTF-8')
Expand All @@ -179,7 +180,7 @@ def save(self):
if action == "confirm":
default_text = get_template_source(['program/receipts/%s_custom_pretext.html' %(self.program.id), 'program/receipts/default_pretext.html'])
elif action == "confirmemail":
default_text = get_template_source(['program/confemails/%s_confemail.txt' %(self.program.id), 'program/confemails/default.txt'])
default_text = get_template_source(['program/confemails/%s_confemail_pretext.html' %(self.program.id),'program/confemails/default_pretext.html'])
elif action == "cancel":
default_text = ""
if cleaned_text == default_text:
Expand Down Expand Up @@ -226,7 +227,7 @@ def __init__(self, *args, **kwargs):
self.fields[key].initial = self.fields[key].default = tag_info.get('default')
self.fields[key].required = False
set_val = Tag.getBooleanTag(key, program = self.program) if tag_info.get('is_boolean', False) else Tag.getProgramTag(key, program = self.program)
if set_val is not None and set_val != self.fields[key].initial:
if set_val != None and set_val != self.fields[key].initial:
if isinstance(self.fields[key], forms.MultipleChoiceField):
set_val = set_val.split(",")
self.fields[key].initial = set_val
Expand Down
11 changes: 7 additions & 4 deletions esp/esp/program/modules/handlers/commmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from esp.users.controllers.usersearch import UserSearchController
from esp.users.views.usersearch import get_user_checklist
from esp.dbmail.models import ActionHandler
from esp.tagdict.models import Tag
from django.template import Template
from django.template import Context as DjangoContext
from esp.middleware import ESPError
Expand Down Expand Up @@ -81,7 +82,7 @@ def commprev(self, request, tl, one, two, module, extra, prog):
# Set From address
if request.POST.get('from', '').strip():
fromemail = request.POST['from']
if not re.match(r"(^.+@%s$)|(^.+@(\w+\.)?learningu\.org$)" % settings.SITE_INFO[1].replace(".", "\."), fromemail):
if not re.match(r'(^.+@{0}$)|(^.+<.+@{0}>$)|(^.+@(\w+\.)?learningu\.org$)|(^.+<.+@(\w+\.)?learningu\.org>$)'.format(settings.SITE_INFO[1].replace('.', '\.')), fromemail):
raise ESPError("Invalid 'From' email address. The 'From' email address must " +
"end in @" + settings.SITE_INFO[1] + " (your website), " +
"@learningu.org, or a valid subdomain of learningu.org " +
Expand All @@ -91,7 +92,8 @@ def commprev(self, request, tl, one, two, module, extra, prog):
prs = PlainRedirect.objects.filter(original = "info")
if not prs.exists():
redirect = PlainRedirect.objects.create(original = "info", destination = settings.DEFAULT_EMAIL_ADDRESSES['default'])
fromemail = '%s@%s' % ("info", settings.SITE_INFO[1])
fromemail = '%s <%s@%s>' % (Tag.getTag('full_group_name') or '%s %s' % (settings.INSTITUTION_NAME, settings.ORGANIZATION_SHORT_NAME),
"info", settings.SITE_INFO[1])

# Set Reply-To address
if request.POST.get('replyto', '').strip():
Expand Down Expand Up @@ -254,7 +256,8 @@ def commpanel(self, request, tl, one, two, module, extra, prog):
if request.method == 'POST':
# Turn multi-valued QueryDict into standard dictionary
data = ListGenModule.processPost(request)

context['default_from'] = '%s <%s@%s>' % (Tag.getTag('full_group_name') or '%s %s' % (settings.INSTITUTION_NAME, settings.ORGANIZATION_SHORT_NAME),
"info", settings.SITE_INFO[1])
## Handle normal list selecting submissions
if ('base_list' in data and 'recipient_type' in data) or ('combo_base_list' in data):

Expand All @@ -275,7 +278,7 @@ def commpanel(self, request, tl, one, two, module, extra, prog):
prs = PlainRedirect.objects.filter(original = "info")
if not prs.exists():
redirect = PlainRedirect.objects.create(original = "info", destination = settings.DEFAULT_EMAIL_ADDRESSES['default'])
context['from'] = '%s@%s' % ("info", settings.SITE_INFO[1])
context['from'] = context['default_from']
return render_to_response(self.baseDir()+'step2.html', request, context)

## Prepare a message starting from an earlier request
Expand Down
7 changes: 4 additions & 3 deletions esp/esp/program/modules/handlers/studentregcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,13 @@ def confirmreg_forreal(self, request, tl, one, two, module, extra, prog, new_reg
else:
raise ESPError("You must finish all the necessary steps first, then click on the Save button to finish registration.", log=False)

cfe = ConfirmationEmailController()
cfe.send_confirmation_email(user, self.program)

# when does class registration close for this user?
context['deadline'] = Permission.user_deadline_when(user, "Student/Classes", prog)

cfe = ConfirmationEmailController()
# this email includes the student's schedule (by default), so send a new email each time they confirm their reg
cfe.send_confirmation_email(user, self.program, context = context, repeat = True)

context["request"] = request
context["program"] = prog
context.update(esp_context_stuff())
Expand Down
20 changes: 20 additions & 0 deletions esp/esp/program/modules/migrations/0044_auto_20240507_2041.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2024-05-07 20:41
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('modules', '0043_auto_20240321_2023'),
]

operations = [
migrations.AlterField(
model_name='studentclassregmoduleinfo',
name='send_confirmation',
field=models.BooleanField(default=True, help_text=b'Check this box to send each student an email each time they confirm their registration. You can customize the text of the email using the "Confirmemail" registration receipt below.'),
),
]
17 changes: 17 additions & 0 deletions esp/esp/program/modules/migrations/0045_merge_20240515_2025.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2024-05-15 20:25
from __future__ import unicode_literals

from __future__ import absolute_import
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('modules', '0044_auto_20240507_2041'),
('modules', '0044_auto_20240509_2341'),
]

operations = [
]
Loading

0 comments on commit d03eab5

Please sign in to comment.