Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions courses/admin/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from django.contrib import messages

from courses.models import Course, ReviewCriteria
from courses.models import Course, ReviewCriteria, CourseRegistration
from courses.scoring import update_leaderboard


Expand Down Expand Up @@ -100,4 +100,29 @@ def duplicate_course(modeladmin, request, queryset):
class CourseAdmin(ModelAdmin):
actions = [update_leaderboard_admin, duplicate_course]
inlines = [CriteriaInline]
list_display = ["title"]
list_display = ["title", "state"]
list_filter = ["state", "finished"]
fieldsets = (
("Basic Information", {
"fields": ("slug", "title", "description", "social_media_hashtag")
}),
("Course State", {
"fields": ("state", "finished", "first_homework_scored")
}),
("Landing Page Content", {
"fields": ("about_content", "video_url", "hero_image_url", "meta_description", "mailchimp_tag"),
"classes": ("collapse",)
}),
("Settings", {
"fields": ("faq_document_url", "min_projects_to_pass", "project_passing_score", "homework_problems_comments_field")
}),
)


@admin.register(CourseRegistration)
class CourseRegistrationAdmin(ModelAdmin):
list_display = ["name", "email", "course", "country", "role", "registered_at", "mailchimp_subscribed"]
list_filter = ["course", "role", "country", "mailchimp_subscribed", "registered_at"]
search_fields = ["name", "email", "comment"]
readonly_fields = ["registered_at", "mailchimp_subscribed"]
date_hierarchy = "registered_at"
235 changes: 235 additions & 0 deletions courses/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
# Country and region data
COUNTRIES = [
("Algeria", "Africa"),
("Angola", "Africa"),
("Benin", "Africa"),
("Botswana", "Africa"),
("Burkina Faso", "Africa"),
("Burundi", "Africa"),
("Cabo Verde", "Africa"),
("Cameroon", "Africa"),
("Central African Republic", "Africa"),
("Chad", "Africa"),
("Comoros", "Africa"),
("Congo", "Africa"),
("Democratic Republic of the Congo", "Africa"),
("Cote d'Ivoire", "Africa"),
("Djibouti", "Africa"),
("Egypt", "Africa"),
("Equatorial Guinea", "Africa"),
("Eritrea", "Africa"),
("Eswatini", "Africa"),
("Ethiopia", "Africa"),
("Gabon", "Africa"),
("Gambia", "Africa"),
("Ghana", "Africa"),
("Guinea", "Africa"),
("Guinea-Bissau", "Africa"),
("Kenya", "Africa"),
("Lesotho", "Africa"),
("Liberia", "Africa"),
("Libya", "Africa"),
("Madagascar", "Africa"),
("Malawi", "Africa"),
("Mali", "Africa"),
("Mauritania", "Africa"),
("Mauritius", "Africa"),
("Morocco", "Africa"),
("Mozambique", "Africa"),
("Namibia", "Africa"),
("Niger", "Africa"),
("Nigeria", "Africa"),
("Rwanda", "Africa"),
("Sao Tome and Principe", "Africa"),
("Senegal", "Africa"),
("Seychelles", "Africa"),
("Sierra Leone", "Africa"),
("Somalia", "Africa"),
("South Africa", "Africa"),
("South Sudan", "Africa"),
("Sudan", "Africa"),
("Tanzania", "Africa"),
("Togo", "Africa"),
("Tunisia", "Africa"),
("Uganda", "Africa"),
("Zambia", "Africa"),
("Zimbabwe", "Africa"),
("Canada", "North America"),
("United States", "North America"),
("United States of America", "North America"),
("Mexico", "North America"),
("Bermuda", "North America"),
("Greenland", "North America"),
("Saint Pierre and Miquelon", "North America"),
("Belize", "North America"),
("Costa Rica", "North America"),
("El Salvador", "North America"),
("Guatemala", "North America"),
("Honduras", "North America"),
("Nicaragua", "North America"),
("Panama", "North America"),
("Cuba", "North America"),
("Dominican Republic", "North America"),
("Haiti", "North America"),
("Jamaica", "North America"),
("Trinidad and Tobago", "North America"),
("Barbados", "North America"),
("Bahamas", "North America"),
("Grenada", "North America"),
("Saint Lucia", "North America"),
("Saint Vincent and the Grenadines", "North America"),
("Dominica", "North America"),
("Antigua and Barbuda", "North America"),
("Saint Kitts and Nevis", "North America"),
("Puerto Rico", "North America"),
("Curacao", "North America"),
("Aruba", "North America"),
("Cayman Islands", "North America"),
("Argentina", "South America"),
("Bolivia", "South America"),
("Brazil", "South America"),
("Chile", "South America"),
("Colombia", "South America"),
("Ecuador", "South America"),
("Guyana", "South America"),
("Paraguay", "South America"),
("Peru", "South America"),
("Suriname", "South America"),
("Uruguay", "South America"),
("Venezuela", "South America"),
("French Guiana", "South America"),
("Falkland Islands", "South America"),
("Afghanistan", "Asia"),
("Armenia", "Asia"),
("Azerbaijan", "Asia"),
("Bahrain", "Asia"),
("Bangladesh", "Asia"),
("Bhutan", "Asia"),
("Brunei", "Asia"),
("Cambodia", "Asia"),
("China", "Asia"),
("Georgia", "Asia"),
("India", "Asia"),
("Indonesia", "Asia"),
("Iran", "Asia"),
("Iraq", "Asia"),
("Israel", "Asia"),
("Japan", "Asia"),
("Jordan", "Asia"),
("Kazakhstan", "Asia"),
("Kuwait", "Asia"),
("Kyrgyzstan", "Asia"),
("Laos", "Asia"),
("Lebanon", "Asia"),
("Malaysia", "Asia"),
("Maldives", "Asia"),
("Mongolia", "Asia"),
("Myanmar", "Asia"),
("Nepal", "Asia"),
("North Korea", "Asia"),
("Oman", "Asia"),
("Pakistan", "Asia"),
("Palestine", "Asia"),
("Philippines", "Asia"),
("Qatar", "Asia"),
("Saudi Arabia", "Asia"),
("Singapore", "Asia"),
("South Korea", "Asia"),
("Sri Lanka", "Asia"),
("Syria", "Asia"),
("Tajikistan", "Asia"),
("Thailand", "Asia"),
("Timor-Leste", "Asia"),
("Turkey", "Asia"),
("Turkmenistan", "Asia"),
("United Arab Emirates", "Asia"),
("Uzbekistan", "Asia"),
("Vietnam", "Asia"),
("Yemen", "Asia"),
("Albania", "Europe"),
("Andorra", "Europe"),
("Austria", "Europe"),
("Belarus", "Europe"),
("Belgium", "Europe"),
("Bosnia and Herzegovina", "Europe"),
("Bulgaria", "Europe"),
("Croatia", "Europe"),
("Cyprus", "Europe"),
("Czechia", "Europe"),
("Denmark", "Europe"),
("Estonia", "Europe"),
("Finland", "Europe"),
("France", "Europe"),
("Germany", "Europe"),
("Greece", "Europe"),
("Hungary", "Europe"),
("Iceland", "Europe"),
("Ireland", "Europe"),
("Italy", "Europe"),
("Kosovo", "Europe"),
("Latvia", "Europe"),
("Liechtenstein", "Europe"),
("Lithuania", "Europe"),
("Luxembourg", "Europe"),
("Malta", "Europe"),
("Moldova", "Europe"),
("Monaco", "Europe"),
("Montenegro", "Europe"),
("Netherlands", "Europe"),
("North Macedonia", "Europe"),
("Norway", "Europe"),
("Poland", "Europe"),
("Portugal", "Europe"),
("Romania", "Europe"),
("Russia", "Europe"),
("San Marino", "Europe"),
("Serbia", "Europe"),
("Slovakia", "Europe"),
("Slovenia", "Europe"),
("Spain", "Europe"),
("Sweden", "Europe"),
("Switzerland", "Europe"),
("Ukraine", "Europe"),
("United Kingdom", "Europe"),
("Vatican City", "Europe"),
("Australia", "Oceania"),
("New Zealand", "Oceania"),
("Fiji", "Oceania"),
("Papua New Guinea", "Oceania"),
("Solomon Islands", "Oceania"),
("Vanuatu", "Oceania"),
("Samoa", "Oceania"),
("Tonga", "Oceania"),
("Kiribati", "Oceania"),
("Tuvalu", "Oceania"),
("Nauru", "Oceania"),
("Micronesia", "Oceania"),
("Palau", "Oceania"),
("Marshall Islands", "Oceania"),
("New Caledonia", "Oceania"),
]

# Role choices for registration
ROLE_CHOICES = [
("data_engineer", "Data Engineer"),
("data_scientist", "Data Scientist"),
("data_analyst", "Data Analyst"),
("ml_engineer", "ML Engineer"),
("software_engineer_backend", "Software Engineer (Backend)"),
("software_engineer_other", "Software Engineer (Frontend, Test, etc)"),
("student_stem", "Student (STEM)"),
("student_non_stem", "Student (Non-STEM)"),
("other", "Other"),
]

# Course state choices
class CourseState:
REGISTRATION = "RE"
ACTIVE = "AC"
FINISHED = "FI"

CHOICES = [
(REGISTRATION, "Registration"),
(ACTIVE, "Active"),
(FINISHED, "Finished"),
]
65 changes: 65 additions & 0 deletions courses/mailchimp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Mailchimp integration for newsletter subscriptions
"""
import os
import logging
import hashlib
import requests

logger = logging.getLogger(__name__)

MAILCHIMP_TOKEN = os.getenv("MAILCHIMP_TOKEN", "")
MAILCHIMP_LIST_ID = os.getenv("MAILCHIMP_LIST_ID", "")


def add_subscriber_to_mailchimp(email: str, tag: str = None) -> bool:
"""
Add or update a subscriber in Mailchimp

Args:
email: The email address to subscribe
tag: Optional tag to add to the subscriber

Returns:
True if successful, False otherwise
"""
if not MAILCHIMP_TOKEN or not MAILCHIMP_LIST_ID:
logger.warning("Mailchimp not configured - skipping subscription")
return False

try:
# Create MD5 hash of lowercase email for subscriber_hash
subscriber_hash = hashlib.md5(email.lower().encode()).hexdigest()

# Prepare the data
data = {
"email_address": email,
"status_if_new": "subscribed",
}

# Add tags if provided
if tag:
data["tags"] = [tag]

# Mailchimp API URL
mc_url = f"https://us19.api.mailchimp.com/3.0/lists/{MAILCHIMP_LIST_ID}/members/{subscriber_hash}"

# Make the request
response = requests.put(
mc_url,
auth=("anystring", MAILCHIMP_TOKEN),
headers={"Content-Type": "application/json"},
json=data,
timeout=10,
)

if response.status_code in [200, 201]:
logger.info(f"Successfully added {email} to Mailchimp with tag {tag}")
return True
else:
logger.error(f"Mailchimp API error: {response.status_code} - {response.text}")
return False

except Exception as e:
logger.error(f"Error adding subscriber to Mailchimp: {e}")
return False
Loading