Skip to content
Open
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
34 changes: 34 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/

**/.DS_Store
**/__pycache__
**/.venv
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ cover/
*.mo
*.pot


*.__pycache__/
# Flask stuff:
instance/
.webassets-cache
Expand Down
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE = 1
ENV PYTHONUNBUFFERED = 1
RUN apt-get update && apt-get install -y gcc python3-dev libpq-dev


WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .


CMD ["gunicorn", "--bind", "0.0.0:8000", "--workers", "4", "main.wsgi:application"]
51 changes: 51 additions & 0 deletions Dockerfile.Celery
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# # syntax=docker/dockerfile:1

# # Comments are provided throughout this file to help you get started.
# # If you need more help, visit the Dockerfile reference guide at
# # https://docs.docker.com/go/dockerfile-reference/

# # Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7

# ARG PYTHON_VERSION=3.13.0
# FROM python:${PYTHON_VERSION}-slim as base

# # Prevents Python from writing pyc files.
# ENV PYTHONDONTWRITEBYTECODE=1

# # Keeps Python from buffering stdout and stderr to avoid situations where
# # the application crashes without emitting any logs due to buffering.
# ENV PYTHONUNBUFFERED=1

# WORKDIR /app

# # Create a non-privileged user that the app will run under.
# # See https://docs.docker.com/go/dockerfile-user-best-practices/
# ARG UID=10001
# RUN adduser \
# --disabled-password \
# --gecos "" \
# --home "/nonexistent" \
# --shell "/sbin/nologin" \
# --no-create-home \
# --uid "${UID}" \
# appuser

# # Download dependencies as a separate step to take advantage of Docker's caching.
# # Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.
# # Leverage a bind mount to requirements.txt to avoid having to copy them into
# # into this layer.
# RUN --mount=type=cache,target=/root/.cache/pip \
# --mount=type=bind,source=requirements.txt,target=requirements.txt \
# python -m pip install -r requirements.txt

# # Switch to the non-privileged user to run the application.
# USER appuser

# # Copy the source code into the container.
# COPY . .

# # Expose the port that the application listens on.
# EXPOSE 8000

# # Run the application.
# CMD gunicorn 'enbv.Lib.site-packages.asgiref.wsgi' --bind=0.0.0.0:8000
22 changes: 22 additions & 0 deletions README.Docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
### Building and running your application

When you're ready, start your application by running:
`docker compose up --build`.

Your application will be available at http://localhost:8000.

### Deploying your application to the cloud

First, build your image, e.g.: `docker build -t myapp .`.
If your cloud uses a different CPU architecture than your development
machine (e.g., you are on a Mac M1 and your cloud provider is amd64),
you'll want to build the image for that platform, e.g.:
`docker build --platform=linux/amd64 -t myapp .`.

Then, push it to your registry, e.g. `docker push myregistry.com/myapp`.

Consult Docker's [getting started](https://docs.docker.com/go/get-started-sharing/)
docs for more detail on building and pushing.

### References
* [Docker's Python guide](https://docs.docker.com/language/python/)
Binary file modified db.sqlite3
Binary file not shown.
Binary file modified event/__pycache__/models.cpython-313.pyc
Binary file not shown.
Binary file modified event/__pycache__/permissions.cpython-313.pyc
Binary file not shown.
Binary file removed event/__pycache__/serializers.cpython-313.pyc
Binary file not shown.
Binary file removed event/__pycache__/urls.cpython-313.pyc
Binary file not shown.
Binary file removed event/__pycache__/views.cpython-313.pyc
Binary file not shown.
2 changes: 1 addition & 1 deletion event/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ def has_permission(self, request, view):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return request.user.profile==obj.creator
return request.user==obj.creator
9 changes: 4 additions & 5 deletions event/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def validate(self, data):
return data

def create(self, validated_data):
"""Create a new user and associate a profile."""

email = validated_data.get("email")
username = validated_data.get("username")
phone_number = validated_data.pop("phone_number", None)
Expand Down Expand Up @@ -108,14 +108,14 @@ def get_creator_phone(self, obj):
return obj.creator.profile.phone_number
except ObjectDoesNotExist:
return None




def create(self, validated_data):
"""Associate the event with the creator."""
validated_data["creator"] = self.context["request"].user
return super().create(validated_data)


class EventDetailSerializer(EventSerializer):
"""Serializer for detailed event view."""

Expand Down Expand Up @@ -144,8 +144,7 @@ def create(self, validated_data):


class ReminderSerializer(serializers.ModelSerializer):
"""Serializer for reminders."""


class Meta:
model = Reminder
fields = ["id", "sent_at", "message", "type"]
76 changes: 40 additions & 36 deletions event/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,7 @@
from celery import shared_task
from .models import Event, Reminder

@shared_task
def send_event_reminders():


tomorrow = timezone.now() + timedelta(days=1)
four_days = timezone.now() + timedelta(days=4)

# Get events in the next 3 days
upcoming_events = Event.objects.filter(
date__gte=tomorrow,
date__lte=four_days
)

for event in upcoming_events:
days_until_event = (event.date - timezone.now()).days

for attendee in event.attendees.all():

if Reminder.objects.filter(
attendee=attendee,
sent_at__date=timezone.now().date()
).exists():
continue


if days_until_event <= 1:
message = f"REMINDER: The event '{event.title}' is TOMORROW at {event.date.strftime('%H:%M')} in {event.location}."
else:
message = f"REMINDER: The event '{event.title}' is coming up in {days_until_event} days at {event.date.strftime('%H:%M')} in {event.location}."

# Send email reminder
send_email_reminder(attendee, event, message)

# Send WhatsApp reminder if phone number is available
if attendee.phone_number:
send_whatsapp_reminder(attendee, message)

def send_email_reminder(attendee, event, message):
"""Send email reminder to an attendee"""
Expand Down Expand Up @@ -79,4 +44,43 @@ def send_whatsapp_reminder(attendee, message):
)

except Exception as e:
print(f"Failed to send WhatsApp reminder: {str(e)}")
print(f"Failed to send WhatsApp reminder: {str(e)}")


@shared_task
def send_event_reminders():


tomorrow = timezone.now() + timedelta(days=1)
four_days = timezone.now() + timedelta(days=4)

# Get events in the next 3 days
upcoming_events = Event.objects.filter(
date__gte=tomorrow,
date__lte=four_days
)

for event in upcoming_events:
days_until_event = (event.date - timezone.now()).days

for attendee in event.attendees.all():

if Reminder.objects.filter(
attendee=attendee,
sent_at__date=timezone.now().date()
).exists():
continue


if days_until_event <= 1:
message = f"REMINDER: The event '{event.title}' is TOMORROW at {event.date.strftime('%H:%M')} in {event.location}."
else:
message = f"REMINDER: The event '{event.title}' is coming up in {days_until_event} days at {event.date.strftime('%H:%M')} in {event.location}."

# Send email reminder
send_email_reminder(attendee, event, message)

# Send WhatsApp reminder if phone number is available
if attendee.phone_number:
send_whatsapp_reminder(attendee, message)

2 changes: 1 addition & 1 deletion event/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

urlpatterns = [
path('', include(router.urls)),
path('google/login/', views.GoogleLoginView.as_view(), name='google-login'),
path('google/login/', views.google, name='google-login'),
path('auth/',include('rest_framework.urls')),
path('logout/', views.logout, name='user-logout'),
path('register/', views.UserRegistrationView.as_view(), name='user-registration'),
Expand Down
Loading