Skip to content

Commit a71607b

Browse files
committed
task celery task
1 parent 907818b commit a71607b

File tree

12 files changed

+244
-10
lines changed

12 files changed

+244
-10
lines changed

README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ The ultimate goal of a task management application is to empower users to manage
2121
- [x] Task Creation and Organization:
2222
Allow users to create tasks easily and organize them based on different parameters such as due dates, priority, categories, and projects.
2323

24-
- Task Tracking and Status Updates:
24+
- [x] Task Tracking and Status Updates:
2525
Enable users to track the progress of their tasks, update task statuses (e.g., to-do, in progress, completed), and get a clear overview of tasks that need attention.
2626

27-
- Deadline Management:
27+
- [x] Deadline Management:
2828
Help users keep track of task deadlines by providing reminders, notifications, and a clear visualization of upcoming due dates.
2929

3030
- Collaboration and Sharing:
@@ -33,10 +33,10 @@ Facilitate collaboration among teams by allowing users to assign tasks to collea
3333
- Time Management:
3434
Provide tools to estimate and track the time required to complete tasks, helping users allocate their time effectively and avoid overloading themselves.
3535

36-
- Prioritization and Sorting:
36+
- [x] Prioritization and Sorting:
3737
Allow users to set task priorities and sort tasks based on importance, urgency, or custom criteria, aiding in making informed decisions about task order.
3838

39-
- Customization:
39+
- [x] Customization:
4040
Offer flexibility in customizing task categories, labels, tags, and views to match users' preferred workflows and organizational methods.
4141

4242
- Data Visualization and Insights:
@@ -110,4 +110,25 @@ The following endpoints are available in the API:
110110
- `api/task/task_view/` (GET): getting all task owned by the logged in user in order or priority and deadline if provided.
111111
- `api/task/task_detail/` (GET): getting a single task.
112112
- `api/task/task_detail/` (PUT): updating a task.
113-
- `api/task/task_detail/` (DELETE): deleting a task.
113+
- `api/task/task_detail/` (DELETE): deleting a task.
114+
- `api/task/tag_view/` (POST): allow users create tag.
115+
- `api/task/tag_view/` (GET): getting all tags owned by the logged in user.
116+
- `api/task/tag_detail/` (GET): getting a single tag.
117+
- `api/task/tag_detail/` (PUT): updating a tag.
118+
- `api/task/tag_detail/` (DELETE): deleting a tag.
119+
- `api/task/category_view/` (POST): allow users create category.
120+
- `api/task/category_view/` (GET): getting all category owned by the logged in user.
121+
- `api/task/category_detail/` (GET): getting a single category.
122+
- `api/task/category_detail/` (PUT): updating a category.
123+
- `api/task/category_detail/` (DELETE): deleting a category.
124+
125+
126+
127+
# Contributing
128+
129+
Contributions to this project are welcome! Go through our [GUIDELINES]()
130+
131+
132+
# License
133+
134+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

src/task_app/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
# Register your models here.
55
admin.site.register(Task)
66
admin.site.register(Tag)
7-
admin.site.register(Category)
7+
admin.site.register(Category)
8+
admin.site.register(Reminder)

src/task_app/apps.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
class TaskAppConfig(AppConfig):
55
default_auto_field = "django.db.models.BigAutoField"
66
name = "task_app"
7+
8+
def ready(self):
9+
import task_app.signals
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Generated by Django 4.2.4 on 2023-08-23 23:40
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
("task_app", "0003_alter_task_deadline"),
13+
]
14+
15+
operations = [
16+
migrations.AddField(
17+
model_name="category",
18+
name="user",
19+
field=models.ForeignKey(
20+
null=True,
21+
on_delete=django.db.models.deletion.CASCADE,
22+
to=settings.AUTH_USER_MODEL,
23+
),
24+
),
25+
migrations.AddField(
26+
model_name="tag",
27+
name="user",
28+
field=models.ForeignKey(
29+
null=True,
30+
on_delete=django.db.models.deletion.CASCADE,
31+
to=settings.AUTH_USER_MODEL,
32+
),
33+
),
34+
migrations.CreateModel(
35+
name="Reminder",
36+
fields=[
37+
(
38+
"id",
39+
models.BigAutoField(
40+
auto_created=True,
41+
primary_key=True,
42+
serialize=False,
43+
verbose_name="ID",
44+
),
45+
),
46+
("notified", models.BooleanField(default=False)),
47+
(
48+
"task",
49+
models.ForeignKey(
50+
on_delete=django.db.models.deletion.CASCADE, to="task_app.task"
51+
),
52+
),
53+
(
54+
"user",
55+
models.ForeignKey(
56+
on_delete=django.db.models.deletion.CASCADE,
57+
to=settings.AUTH_USER_MODEL,
58+
),
59+
),
60+
],
61+
),
62+
]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.4 on 2023-08-23 23:49
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("task_app", "0004_category_user_tag_user_reminder"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="reminder",
15+
name="reminder_time",
16+
field=models.DateTimeField(blank=True, null=True),
17+
),
18+
]

src/task_app/models.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Create your models here.
66

77
class Category(models.Model):
8-
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
8+
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, null=True)
99
name = models.CharField(max_length=50)
1010

1111
def __str__(self):
@@ -17,7 +17,7 @@ class Meta:
1717

1818

1919
class Tag(models.Model):
20-
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
20+
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, null=True)
2121
name = models.CharField(max_length=50)
2222

2323
def __str__(self):
@@ -51,3 +51,13 @@ class Task(models.Model):
5151

5252
def __str__(self):
5353
return self.title
54+
55+
56+
class Reminder(models.Model):
57+
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
58+
task = models.ForeignKey(Task, on_delete=models.CASCADE)
59+
reminder_time = models.DateTimeField(null=True, blank=True)
60+
notified = models.BooleanField(default=False)
61+
62+
def __str__(self) -> str:
63+
return f"{self.user.first_name}'s reminder"

src/task_app/signals.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from django.db.models.signals import post_save
2+
from .models import Task, Reminder
3+
from django.dispatch import receiver
4+
from datetime import timedelta
5+
from django.utils import timezone
6+
7+
8+
9+
@receiver(post_save, sender=Task)
10+
def create_reminder(sender, instance, created, **kwargs):
11+
if created and instance.deadline:
12+
reminder_time = instance.deadline - timedelta(minutes=20) #send reminder 20mins before the deadline
13+
if reminder_time > timezone.now():
14+
Reminder.objects.create(
15+
user=instance.user,
16+
task=instance,
17+
reminder_time=reminder_time
18+
)

src/task_app/tasks.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from django.utils import timezone
2+
from .models import Reminder
3+
from datetime import timedelta
4+
from django.core.mail import send_mail
5+
from celery.utils.log import get_task_logger
6+
from celery import shared_task
7+
8+
9+
logger = get_task_logger(__name__)
10+
11+
12+
@shared_task()
13+
def send_task_reminder():
14+
now = timezone.now()
15+
near_reminders = Reminder.objects.filter(reminder_time__gte=now, reminder_time__lte=now + timedelta(minutes=15), notified=False)
16+
17+
for reminder in near_reminders:
18+
# Send a reminder notification
19+
send_mail(
20+
'Reminder',
21+
f"Your reminder for '{reminder.task}' is due soon.",
22+
'noreply@example.com',
23+
[reminder.user.email],
24+
fail_silently=False,
25+
)
26+
27+
reminder.notified = True
28+
reminder.save()

src/task_app/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@
66
path("task_detail/<str:pk>/", TaskDetail.as_view()),
77
path("tag_view/", TagView.as_view()),
88
path("tag_detail/<str:pk>/", TaskDetail.as_view()),
9+
path("category_view/", CategoryView.as_view()),
10+
path("category_detail/<str:pk>/", CategoryDetail.as_view()),
911
]

src/task_app/views.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,19 @@ class TaskView(APIView):
1818
list all task or create a new task
1919
"""
2020
def get(self, request, format=None):
21+
if "category" in request.GET:
22+
category = request.GET["category"]
23+
categoryid = get_object_or_404(Category, name=category).id
24+
tasks = get_list_or_404(Task, user=request.user, category=categoryid)
25+
serializer = TaskSerializer(tasks, many=True)
26+
return Response(serializer.data)
27+
elif "tag" in request.GET:
28+
tag = request.GET["tag"]
29+
tagid = get_object_or_404(Tag, user=request.user, name=tag).id
30+
tags = get_list_or_404(Task, user=request.user, tag=tagid)
31+
serializer = TagSerializer(tags, many=True)
32+
return Response(serializer.data)
33+
2134
tasks = Task.objects.filter(user=request.user).order_by('priority', 'deadline')
2235
serializer = TaskSerializer(tasks, many=True)
2336
return Response(serializer.data)
@@ -97,6 +110,49 @@ def get(self, request, pk, format=None):
97110
serializer = TagSerializer(tag)
98111
return Response(serializer.data)
99112

113+
def put(self, request, pk, format=None):
114+
tag = self.get_object(pk)
115+
serializer = TagSerializer(tag, data=request.data)
116+
if serializer.is_valid():
117+
serializer.save()
118+
return Response(serializer.data)
119+
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
120+
121+
122+
class CategoryView(APIView):
123+
permission_classes = [IsAuthenticated]
124+
"""
125+
list all task or create a new task
126+
"""
127+
def get(self, request, format=None):
128+
tags = Tag.objects.filter(user=request.user)
129+
serializer = TagSerializer(tags, many=True)
130+
return Response(serializer.data)
131+
132+
def post(self, request, format=None):
133+
serializer = TagSerializer(data=request.data)
134+
if serializer.is_valid():
135+
serializer.save()
136+
return Response(serializer.data, status=status.HTTP_201_CREATED)
137+
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
138+
139+
140+
class CategoryDetail(APIView):
141+
permission_classes = [IsAuthenticated]
142+
"""
143+
Retrieve, update or delete a snippet instance.
144+
"""
145+
def get_object(self, pk):
146+
try:
147+
return Tag.objects.get(pk=pk)
148+
except Tag.DoesNotExist:
149+
raise Http404
150+
151+
def get(self, request, pk, format=None):
152+
tag = self.get_object(pk)
153+
serializer = TagSerializer(tag)
154+
return Response(serializer.data)
155+
100156
def put(self, request, pk, format=None):
101157
tag = self.get_object(pk)
102158
serializer = TagSerializer(tag, data=request.data)

0 commit comments

Comments
 (0)