mirror of
https://github.com/lemeow125/DRF_Template.git
synced 2024-11-17 04:09:25 +08:00
Compare commits
2 commits
b024a74364
...
e79a1777c1
Author | SHA1 | Date | |
---|---|---|---|
e79a1777c1 | |||
f7b949a45e |
8 changed files with 44 additions and 31 deletions
|
@ -2,5 +2,12 @@ firefox/
|
||||||
chrome/
|
chrome/
|
||||||
dumps/
|
dumps/
|
||||||
media/
|
media/
|
||||||
TODO.md
|
static/
|
||||||
.env
|
documentation/
|
||||||
|
.env
|
||||||
|
.venv/
|
||||||
|
.vscode/
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.woodpecker/
|
||||||
|
**/__pycache__/
|
||||||
|
|
|
@ -23,11 +23,13 @@ A live API demo can be found [here](https://api.template.06222001.xyz/api/v1/swa
|
||||||
- Populate .env with values
|
- Populate .env with values
|
||||||
- Run `docker-compose -f docker-compose.dev.yml up`
|
- Run `docker-compose -f docker-compose.dev.yml up`
|
||||||
|
|
||||||
When using `docker-compose.dev.yml`, the entire project directory is mounted onto the container allowing for hot-reloading. Make sure DEBUG is set to True for this to work! Be sure to follow through the steps shown in the `stripe-listener` container for initial setup with Stripe!
|
When using `docker-compose.dev.yml`, the entire project directory is mounted onto the container allowing for hot-reloading. This requires `DEBUG` to be set to `True`.
|
||||||
|
|
||||||
|
Also make sure to follow through the steps shown in the `stripe-listener` container for initial setup with Stripe.
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
A sample `docker-compose.yml` is provided which I use in hosting the demo. DEBUG should be set to False when deploying as to not expose the URLs fro Celery Flower and the Django Silk Profiler. The local Inbucket container is not present so make sure to specify an external SMTP server to process emails properly.
|
A sample `docker-compose.yml` is provided which I use in hosting the demo. `DEBUG` should be set to `False` when deploying as to not expose the URLs fro Celery Flower and the Django Silk Profiler. The local Inbucket container is not present with `DEBUG` turned off so make sure to specify an external SMTP server to process emails properly.
|
||||||
|
|
||||||
### URLs
|
### URLs
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from config.settings import ROOT_DIR, SEED_DATA, get_secret
|
from config.settings import ROOT_DIR, SEED_DATA, TIME_ZONE, get_secret
|
||||||
from django.db.models.signals import post_migrate
|
from django.db.models.signals import post_migrate
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django_celery_beat.models import CrontabSchedule, PeriodicTask
|
from django_celery_beat.models import CrontabSchedule, PeriodicTask
|
||||||
|
@ -64,7 +64,7 @@ def create_celery_beat_schedules(sender, **kwargs):
|
||||||
day_of_week=schedule["day_of_week"],
|
day_of_week=schedule["day_of_week"],
|
||||||
day_of_month=schedule["day_of_month"],
|
day_of_month=schedule["day_of_month"],
|
||||||
month_of_year=schedule["month_of_year"],
|
month_of_year=schedule["month_of_year"],
|
||||||
timezone=schedule["timezone"],
|
timezone=TIME_ZONE,
|
||||||
).first()
|
).first()
|
||||||
# If it does not exist, create a new Schedule
|
# If it does not exist, create a new Schedule
|
||||||
if not SCHEDULE:
|
if not SCHEDULE:
|
||||||
|
@ -74,14 +74,16 @@ def create_celery_beat_schedules(sender, **kwargs):
|
||||||
day_of_week=schedule["day_of_week"],
|
day_of_week=schedule["day_of_week"],
|
||||||
day_of_month=schedule["day_of_month"],
|
day_of_month=schedule["day_of_month"],
|
||||||
month_of_year=schedule["month_of_year"],
|
month_of_year=schedule["month_of_year"],
|
||||||
timezone=schedule["timezone"],
|
timezone=TIME_ZONE,
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
f"Created Crontab Schedule for Hour:{SCHEDULE.hour},Minute:{SCHEDULE.minute}"
|
f"Created Crontab Schedule for Hour:{
|
||||||
|
SCHEDULE.hour},Minute:{SCHEDULE.minute}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f"Crontab Schedule for Hour:{SCHEDULE.hour},Minute:{SCHEDULE.minute} already exists"
|
f"Crontab Schedule for Hour:{SCHEDULE.hour},Minute:{
|
||||||
|
SCHEDULE.minute} already exists"
|
||||||
)
|
)
|
||||||
for task in seed_data["scheduled_tasks"]:
|
for task in seed_data["scheduled_tasks"]:
|
||||||
TASK = PeriodicTask.objects.filter(name=task["name"]).first()
|
TASK = PeriodicTask.objects.filter(name=task["name"]).first()
|
||||||
|
@ -93,7 +95,7 @@ def create_celery_beat_schedules(sender, **kwargs):
|
||||||
day_of_week=task["schedule"]["day_of_week"],
|
day_of_week=task["schedule"]["day_of_week"],
|
||||||
day_of_month=task["schedule"]["day_of_month"],
|
day_of_month=task["schedule"]["day_of_month"],
|
||||||
month_of_year=task["schedule"]["month_of_year"],
|
month_of_year=task["schedule"]["month_of_year"],
|
||||||
timezone=task["schedule"]["timezone"],
|
timezone=TIME_ZONE,
|
||||||
).first()
|
).first()
|
||||||
TASK = PeriodicTask.objects.create(
|
TASK = PeriodicTask.objects.create(
|
||||||
crontab=SCHEDULE,
|
crontab=SCHEDULE,
|
||||||
|
|
|
@ -41,7 +41,8 @@ class CustomUserViewSet(DjoserUserViewSet):
|
||||||
key = f"usergroup_users:{user.user_group.id}"
|
key = f"usergroup_users:{user.user_group.id}"
|
||||||
queryset = cache.get(key)
|
queryset = cache.get(key)
|
||||||
if not queryset:
|
if not queryset:
|
||||||
queryset = CustomUser.objects.filter(user_group=user.user_group)
|
queryset = CustomUser.objects.filter(
|
||||||
|
user_group=user.user_group)
|
||||||
cache.set(key, queryset, 60 * 60)
|
cache.set(key, queryset, 60 * 60)
|
||||||
return queryset
|
return queryset
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -9,6 +9,8 @@ class ActivationEmail(email.ActivationEmail):
|
||||||
class PasswordResetEmail(email.PasswordResetEmail):
|
class PasswordResetEmail(email.PasswordResetEmail):
|
||||||
template_name = "password_change.html"
|
template_name = "password_change.html"
|
||||||
|
|
||||||
|
# TODO: Fix email template values not filling in properly
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionAvailedEmail(email.BaseEmailMessage):
|
class SubscriptionAvailedEmail(email.BaseEmailMessage):
|
||||||
template_name = "subscription_availed.html"
|
template_name = "subscription_availed.html"
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
|
from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class Notification(models.Model):
|
class Notification(models.Model):
|
||||||
recipient = models.ForeignKey("accounts.CustomUser", on_delete=models.CASCADE)
|
recipient = models.ForeignKey(
|
||||||
|
"accounts.CustomUser", on_delete=models.CASCADE)
|
||||||
content = models.CharField(max_length=1000, null=True)
|
content = models.CharField(max_length=1000, null=True)
|
||||||
timestamp = models.DateTimeField(auto_now_add=True, editable=False)
|
timestamp = models.DateTimeField(auto_now_add=True, editable=False)
|
||||||
dismissed = models.BooleanField(default=False)
|
dismissed = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.content
|
return self.content
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
cache.delete(f"notifications_user:{self.recipient.id}")
|
||||||
|
super().save(**kwargs)
|
||||||
|
|
|
@ -3,12 +3,14 @@ from notifications.models import Notification
|
||||||
from notifications.serializers import NotificationSerializer
|
from notifications.serializers import NotificationSerializer
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
|
|
||||||
class NotificationViewSet(viewsets.ModelViewSet):
|
class NotificationViewSet(viewsets.ModelViewSet):
|
||||||
http_method_names = ["get", "patch", "delete"]
|
http_method_names = ["get", "delete"]
|
||||||
serializer_class = NotificationSerializer
|
serializer_class = NotificationSerializer
|
||||||
queryset = Notification.objects.all()
|
queryset = Notification.objects.all()
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
|
@ -21,18 +23,14 @@ class NotificationViewSet(viewsets.ModelViewSet):
|
||||||
cache.set(key, queryset, 60 * 60)
|
cache.set(key, queryset, 60 * 60)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def update(self, request, *args, **kwargs):
|
|
||||||
instance = self.get_object()
|
|
||||||
if instance.recipient != request.user:
|
|
||||||
raise PermissionDenied(
|
|
||||||
"You do not have permission to update this notification."
|
|
||||||
)
|
|
||||||
return super().update(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
|
user = self.request.user
|
||||||
if instance.recipient != request.user:
|
if instance.recipient != request.user:
|
||||||
raise PermissionDenied(
|
raise PermissionDenied(
|
||||||
"You do not have permission to delete this notification."
|
"You do not have permission to delete this notification."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cache.delete(f"notifications_user:{user.id}")
|
||||||
|
|
||||||
return super().destroy(request, *args, **kwargs)
|
return super().destroy(request, *args, **kwargs)
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
"hour": "0",
|
"hour": "0",
|
||||||
"day_of_week": "*",
|
"day_of_week": "*",
|
||||||
"day_of_month": "*",
|
"day_of_month": "*",
|
||||||
"month_of_year": "*",
|
"month_of_year": "*"
|
||||||
"timezone": "Asia/Manila"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "crontab",
|
"type": "crontab",
|
||||||
|
@ -15,8 +14,7 @@
|
||||||
"hour": "1",
|
"hour": "1",
|
||||||
"day_of_week": "*",
|
"day_of_week": "*",
|
||||||
"day_of_month": "*",
|
"day_of_month": "*",
|
||||||
"month_of_year": "*",
|
"month_of_year": "*"
|
||||||
"timezone": "Asia/Manila"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "crontab",
|
"type": "crontab",
|
||||||
|
@ -24,8 +22,7 @@
|
||||||
"hour": "12",
|
"hour": "12",
|
||||||
"day_of_week": "*",
|
"day_of_week": "*",
|
||||||
"day_of_month": "*",
|
"day_of_month": "*",
|
||||||
"month_of_year": "*",
|
"month_of_year": "*"
|
||||||
"timezone": "Asia/Manila"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "crontab",
|
"type": "crontab",
|
||||||
|
@ -33,8 +30,7 @@
|
||||||
"hour": "13",
|
"hour": "13",
|
||||||
"day_of_week": "*",
|
"day_of_week": "*",
|
||||||
"day_of_month": "*",
|
"day_of_month": "*",
|
||||||
"month_of_year": "*",
|
"month_of_year": "*"
|
||||||
"timezone": "Asia/Manila"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scheduled_tasks": [
|
"scheduled_tasks": [
|
||||||
|
@ -47,8 +43,7 @@
|
||||||
"hour": "1",
|
"hour": "1",
|
||||||
"day_of_week": "*",
|
"day_of_week": "*",
|
||||||
"day_of_month": "*",
|
"day_of_month": "*",
|
||||||
"month_of_year": "*",
|
"month_of_year": "*"
|
||||||
"timezone": "Asia/Manila"
|
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue