diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..5a7bca36 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +web: gunicorn hiss.wsgi:application --log-file - +worker: celery -A hiss.celery worker --loglevel=info \ No newline at end of file diff --git a/hiss/Procfile b/hiss/Procfile deleted file mode 100644 index d48c4bff..00000000 --- a/hiss/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -web: gunicorn hiss.wsgi --log-file - -worker: celery -A hiss worker --loglevel=info \ No newline at end of file diff --git a/hiss/application/emails.py b/hiss/application/emails.py index 052c8dcb..be1c1e20 100644 --- a/hiss/application/emails.py +++ b/hiss/application/emails.py @@ -26,10 +26,7 @@ def send_creation_email(app: Application) -> None: "organizer_email": settings.ORGANIZER_EMAIL, } - # send_html_email is threaded from the User class - # see user/models.py - - app.user.send_html_email.delay(template_name, context, subject) + app.user.send_html_email(template_name, context, subject) @shared_task def send_confirmation_email(app_id: int) -> None: diff --git a/hiss/application/fixtures/schools.json b/hiss/application/fixtures/schools.json index 38c267dd..8a5fad80 100644 --- a/hiss/application/fixtures/schools.json +++ b/hiss/application/fixtures/schools.json @@ -10984,7 +10984,7 @@ }, { "model": "application.school", - "pk": 2074, + "pk": 2075, "fields": { "name": "Texas A&M University - San Antonio" } @@ -14519,7 +14519,7 @@ }, { "model": "application.school", - "pk": 2075, + "pk": 2074, "fields": { "name": "Other" } diff --git a/hiss/application/models.py b/hiss/application/models.py index d6847a6e..df165475 100644 --- a/hiss/application/models.py +++ b/hiss/application/models.py @@ -401,92 +401,7 @@ class Application(models.Model): user = models.ForeignKey("user.User", on_delete=models.CASCADE, null=False) status = models.CharField( choices=STATUS_OPTIONS, max_length=1, default=STATUS_PENDING - ) - - # def get_next_meal_group(self): - # """ - # Determines the next meal group considering frontloading for restricted groups - # using the RESTRICTED_FRONTLOAD_FACTOR. - # """ - # RESTRICTED_FRONTLOAD_FACTOR = 1.3 - - # meal_groups = ['A', 'B', 'C', 'D'] - # group_distribution = {group: 0 for group in meal_groups} - # restricted_distribution = {group: 0 for group in meal_groups} - # total_confirmed = Application.objects.filter(status='C').exclude(meal_group__isnull=True) - - # for group in meal_groups: - # group_distribution[group] = total_confirmed.filter(meal_group=group).count() - # restricted_distribution[group] = total_confirmed.filter( - # meal_group=group, - # dietary_restrictions__icontains="Vegetarian" - # ).count() + total_confirmed.filter( - # meal_group=group, - # dietary_restrictions__icontains="No-Beef" - # ).count() + total_confirmed.filter( - # meal_group=group, - # dietary_restrictions__icontains="No-Pork" - # ).count() + total_confirmed.filter( - # meal_group=group, - # dietary_restrictions__icontains="Food-Allergy" - # ).count() - - # total_apps = sum(group_distribution.values()) - # total_restricted = sum(restricted_distribution.values()) - # if total_apps == 0: - # return meal_groups[0] - - # base_restricted_percent = total_restricted / total_apps if total_apps else 0 - # target_restricted_percent = { - # group: base_restricted_percent * (RESTRICTED_FRONTLOAD_FACTOR if i < len(meal_groups) // 2 else 1.0) - # for i, group in enumerate(meal_groups) - # } - # target_restricted_count = { - # group: target_restricted_percent[group] * group_distribution[group] if group_distribution[group] > 0 else 0 - # for group in meal_groups - # } - - # restricted_gap = { - # group: target_restricted_count[group] - restricted_distribution[group] - # for group in meal_groups - # } - # prioritized_group = max(restricted_gap, key=restricted_gap.get) - - # last_assigned_group = ( - # total_confirmed.order_by('-datetime_submitted') - # .values_list('meal_group', flat=True) - # .first() - # ) - # if last_assigned_group: - # next_index = (meal_groups.index(last_assigned_group) + 1) % len(meal_groups) - # else: - # next_index = 0 - - # # use frontloaded group if it aligns with round-robin or is significantly better - # if prioritized_group == meal_groups[next_index]: - # return meal_groups[next_index] - # elif restricted_gap[prioritized_group] > restricted_gap[meal_groups[next_index]]: - # return prioritized_group - # else: - # return meal_groups[next_index] - - # def assign_meal_group(self): - # """ - # Assigns a meal group based on the current status and dietary restrictions. - # """ - # if self.status == 'C': # Confirmed - # self.meal_group = self.get_next_meal_group() - # elif self.status == 'E': # Waitlisted - # self.meal_group = 'E' - # else: - # self.meal_group = None - - # def save(self, *args, **kwargs): - # """ - # Overrides save to ensure meal group assignment logic is applied. - # """ - # self.assign_meal_group() - # super().save(*args, **kwargs) + ) # ABOUT YOU first_name = models.CharField( diff --git a/hiss/application/views.py b/hiss/application/views.py index 88a116c7..128959de 100644 --- a/hiss/application/views.py +++ b/hiss/application/views.py @@ -6,7 +6,7 @@ from django.shortcuts import redirect from django.urls import reverse_lazy from django.views import generic -from django.db import transaction + from application.emails import send_confirmation_email, send_creation_email from application.forms import ApplicationModelForm from application.models import ( @@ -103,10 +103,9 @@ def post(self, request: HttpRequest, *args, **kwargs): raise PermissionDenied( "You can't confirm your application if it hasn't been approved." ) - with transaction.atomic(): - app.status = STATUS_CONFIRMED - app.save() - send_confirmation_email(app) + app.status = STATUS_CONFIRMED + app.save() + send_confirmation_email(app) return redirect(reverse_lazy("status")) diff --git a/hiss/customauth/views.py b/hiss/customauth/views.py index 34e3a6ec..12b67b69 100644 --- a/hiss/customauth/views.py +++ b/hiss/customauth/views.py @@ -7,7 +7,7 @@ from django.http import HttpResponse from django.shortcuts import redirect, render, get_object_or_404 from django.urls import reverse_lazy -from django.utils.encoding import force_bytes, force_str +from django.utils.encoding import force_bytes, force_text from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode from django.views import generic @@ -26,7 +26,7 @@ def send_confirmation_email(curr_domain: RequestSite, user: User) -> None: "event_name": settings.EVENT_NAME, "organizer_name": settings.ORGANIZER_NAME, } - user.send_html_email.delay(template_name, context, subject) + user.send_html_email(template_name, context, subject) # Create your views here. @@ -58,7 +58,7 @@ class ActivateView(views.View): def get(self, request, *_args, **kwargs): user = None try: - uid = force_str(urlsafe_base64_decode(kwargs["uidb64"])) + uid = force_text(urlsafe_base64_decode(kwargs["uidb64"])) user = get_user_model().objects.get(id=int(uid)) except ( TypeError, diff --git a/hiss/hiss/celery.py b/hiss/hiss/celery.py index af82effb..e4aa9aa6 100644 --- a/hiss/hiss/celery.py +++ b/hiss/hiss/celery.py @@ -1,22 +1,29 @@ from __future__ import absolute_import, unicode_literals import os +import ssl from celery import Celery # Set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hiss.settings.dev') -app = Celery('hiss') +app = Celery('hiss', + broker_use_ssl={ + 'ssl_cert_reqs': ssl.CERT_NONE, + }, + redis_backend_use_ssl = { + 'ssl_cert_reqs': ssl.CERT_NONE, + } + ) # Using a string here so the worker doesn't have to serialize the object to child processes. app.config_from_object('django.conf:settings', namespace='CELERY') -# Load task modules from all registered Django app configs. -app.autodiscover_tasks() - # Celery configuration for Redis as the broker and result backend app.conf.broker_url = os.environ.get('REDIS_URL', 'redis://localhost:6379/0') app.conf.result_backend = os.environ.get('REDIS_URL', 'redis://localhost:6379/0') +# Load task modules from all registered Django app configs. +app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): diff --git a/hiss/hiss/settings/base.py b/hiss/hiss/settings/base.py index cec92994..9cabdec6 100644 --- a/hiss/hiss/settings/base.py +++ b/hiss/hiss/settings/base.py @@ -118,7 +118,7 @@ AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY") AWS_S3_BUCKET_NAME = "2025-th-resumes" AWS_S3_KEY_PREFIX = "prod" - +ALLOWED_HOSTS = ['*',"https://register.tamuhack.com/","http://register.tamuhack.com/","register.tamuhack.com/","register.tamuhack.com", 'localhost', '127.0.0.1'] STATIC_URL = "/" + BASE_PATHNAME + "static/" STATICFILES_DIRS = [os.path.join(BASE_DIR, "..", "static/")] STATIC_ROOT = "public/" diff --git a/hiss/hiss/settings/deployment.py b/hiss/hiss/settings/deployment.py index b6762692..fb98ab8f 100644 --- a/hiss/hiss/settings/deployment.py +++ b/hiss/hiss/settings/deployment.py @@ -7,7 +7,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False -ALLOWED_HOSTS = ["register.tamuhack.com", 'localhost', '127.0.0.1'] +ALLOWED_HOSTS = ['*',"https://register.tamuhack.com/","http://register.tamuhack.com/","register.tamuhack.com/","register.tamuhack.com", 'localhost', '127.0.0.1'] SESSION_COOKIE_SECURE = False SECURE_BROWSER_XSS_FILTER = False CSRF_COOKIE_SECURE = False diff --git a/hiss/user/models.py b/hiss/user/models.py index a1d0aefd..4c55610e 100644 --- a/hiss/user/models.py +++ b/hiss/user/models.py @@ -74,18 +74,11 @@ class User(auth_models.AbstractUser): USERNAME_FIELD = "email" REQUIRED_FIELDS = [] - @shared_task - def send_html_email(template_name, context, subject, recipient_email): - """Celery task to send an HTML email.""" + def send_html_email(self, template_name, context, subject): + """Send an HTML email to the user.""" html_msg = render_to_string(template_name, context) plain_msg = strip_tags(html_msg) - send_mail( - subject=subject, - message=plain_msg, - from_email=settings.ORGANIZER_EMAIL, - recipient_list=[recipient_email], - html_message=html_msg, - ) + self.email_user(subject, plain_msg, from_email=None, html_message=html_msg) @receiver(post_save, sender=settings.AUTH_USER_MODEL)