Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notif update #913

Merged
merged 14 commits into from
Dec 1, 2023
27 changes: 27 additions & 0 deletions backend/notifications/migrations/0003_auto_20231122_2154.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 3.2.14 on 2023-11-22 16:24

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("notifications", "0002_auto_20231013_0926"),
]

operations = [
migrations.AlterModelOptions(
name="notification",
options={"ordering": ("-created_at",)},
),
migrations.AlterField(
model_name="notification",
name="notification_type",
field=models.CharField(
choices=[
("publish_project", "Publish Project"),
("task_reject", "Task Reject"),
],
max_length=200,
),
),
]
9 changes: 8 additions & 1 deletion backend/notifications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

# Create your models here.
PUBLISH_PROJECT = "publish_project"
NOTIF_TYPES = ((PUBLISH_PROJECT, "Publish Project"),)
TASK_UPADTE = "task_reject"
NOTIF_TYPES = (
(PUBLISH_PROJECT, "Publish Project"),
(TASK_UPADTE, "Task Reject"),
)


class Notification(models.Model):
Expand All @@ -16,5 +20,8 @@ class Notification(models.Model):
on_click = models.URLField(blank=True, null=True)
metadata_json = models.JSONField(blank=True, null=True)

class Meta:
ordering = ("-created_at",)

def __str__(self) -> str:
return f"{self.title} notification"
81 changes: 57 additions & 24 deletions backend/notifications/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
from projects.models import Project
import json
from django.db import models
from datetime import datetime


@shared_task
def createNotificationHandler(
title, notification_type, annotators_ids, reviewers_ids, super_checkers_ids
):
def createNotificationHandler(title, project_id, notification_type, users_ids):
"""this is called after project has published"""
if notification_type == "publish_project":
createNotificationPublishProject(
title, notification_type, annotators_ids, reviewers_ids, super_checkers_ids
)
elif notification_type == "task_update":
pass
createNotificationPublishProject(title, notification_type, users_ids)
elif notification_type == "task_rejection":
createNotificationTaskRejection(title, project_id, notification_type, users_ids)
# this will be called for task one, yet to create it when aggregation part is done
elif notification_type == "dataset_create":
createNotificationDataset(title, notification_type, users_ids)
else:
print("Cannot create notifications")

Expand All @@ -39,31 +38,65 @@ def deleteNotification(user):


@shared_task
def createNotificationPublishProject(
title, project_type, annotators_ids, reviewers_ids, super_checkers_ids
):
def createNotificationPublishProject(title, notification_type, users_ids):
new_notif = Notification(
notification_type=project_type,
notification_type=notification_type,
title=title,
metadata_json="null",
)
new_notif.save()
for a_id in annotators_ids:
for u_id in users_ids:
try:
receiver_user = User.objects.get(id=a_id)
receiver_user = User.objects.get(id=u_id)
new_notif.reciever_user_id.add(receiver_user)
except Exception as e:
return HttpResponse(f"Bad Request. User with ID: {a_id} does not exist.")
for r_id in reviewers_ids:
try:
receiver_user = User.objects.get(id=r_id)
new_notif.reciever_user_id.add(receiver_user)
except Exception as e:
return HttpResponse(f"Bad Request. User with ID: {r_id} does not exist.")
for s_id in super_checkers_ids:
return HttpResponse(f"Bad Request. User with ID: {u_id} does not exist.")
print(f"Notification successfully created- {title}")


@shared_task
def createNotificationDataset(title, project_type, users_ids):
"""this function is for creating notifications when dataset is created and members are users associated with it"""
new_notif = Notification(
notification_type=project_type,
title=title,
metadata_json="null",
)
new_notif.save()
for m_id in users_ids:
try:
receiver_user = User.objects.get(id=s_id)
receiver_user = User.objects.get(id=m_id)
new_notif.reciever_user_id.add(receiver_user)
except Exception as e:
return HttpResponse(f"Bad Request. User with ID: {s_id} does not exist.")
return HttpResponse(f"Bad Request. User with ID: {m_id} does not exist.")
print(f"Notification successfully created- {title}")


@shared_task
def createNotificationTaskRejection(title, project_id, notification_type, users_ids):
users_ids.sort()
existing_notif = Notification.objects.filter(
notification_type="task_reject", title__icontains=str(project_id)
)
for en in existing_notif:
existing_notif_receivers = en.reciever_user_id.all()
existing_notif_receivers_ids = [e.id for e in existing_notif_receivers]
if users_ids == sorted(existing_notif_receivers_ids):
existing_notif.created_at = datetime.now()
existing_notif.save()
else:
new_notif = Notification(
notification_type=notification_type,
title=title,
metadata_json="null",
)
new_notif.save()
for u_id in users_ids:
try:
receiver_user = User.objects.get(id=u_id)
new_notif.reciever_user_id.add(receiver_user)
except Exception as e:
return HttpResponse(
f"Bad Request. User with ID: {u_id} does not exist."
)
return HttpResponse(f"Notification aggregated successfully")
8 changes: 2 additions & 6 deletions backend/notifications/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@
# Create your views here.


def createNotification(
title, notification_type, annotators_ids, reviewers_ids, super_checkers_ids
):
def createNotification(request, title, project_id, notification_type, users_ids=[]):
"""calling shared task of notification creation from tasks"""
createNotificationHandler.delay(
title, notification_type, annotators_ids, reviewers_ids, super_checkers_ids
)
createNotificationHandler(title, project_id, notification_type, users_ids)


def viewNotifications(request):
Expand Down
27 changes: 22 additions & 5 deletions backend/projects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

from workspaces.decorators import is_particular_workspace_manager
from users.utils import generate_random_string
from notifications.views import createNotification,viewNotifications
from notifications.views import createNotification, viewNotifications
import json

# Create your views here.
Expand All @@ -85,6 +85,7 @@
EMAIL_REGEX = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"

PROJECT_IS_PUBLISHED_ERROR = {"message": "This project is already published!"}
INCOMPLETE = "incomplete"


def get_task_field(annotation_json, field):
Expand Down Expand Up @@ -375,7 +376,7 @@ def get_review_reports(proj_id, userid, start_date, end_date):
"Average Rejection Loop Value": round(avg_rejection_loop_value, 2),
"Tasks Rejected Maximum Time": tasks_rejected_max_times,
}

if is_translation_project or proj_type in [
"SemanticTextualSimilarity_Scale5",
"OCRTranscriptionEditing",
Expand Down Expand Up @@ -747,6 +748,7 @@ def get_project_export_status(pk):
"Synchronously Completed. No Time.",
)


def get_task_creation_status(pk) -> str:
"""Function to return the status of the tasks of project that is queried.
Args:
Expand Down Expand Up @@ -775,6 +777,7 @@ def get_task_creation_status(pk) -> str:
return task_creation_status_modified[task_creation_status]
return ""


def get_project_creation_status(pk) -> str:
# sourcery skip: use-named-expression
"""Function to return the status of the project that is queried.
Expand Down Expand Up @@ -4150,7 +4153,7 @@ def project_publish(self, request, pk=None, *args, **kwargs):
serializer = ProjectUsersSerializer(project, many=False)
# ret_dict = serializer.data
annotators = serializer.data["annotators"]
reviewers=serializer.data["annotation_reviewers"]
reviewers = serializer.data["annotation_reviewers"]
super_checkers = serializer.data["review_supercheckers"]
if len(annotators) < project.required_annotators_per_task:
ret_dict = {
Expand All @@ -4177,14 +4180,28 @@ def project_publish(self, request, pk=None, *args, **kwargs):
project.is_published = True
project.published_at = datetime.now()
# creating notifications
title = f"{project.id} - {project.title} has been published."
remaining_tasks = len(
Task.objects.filter(project_id=project, task_status=INCOMPLETE)
)
title = f"{project.id} - {project.title} has been published. {remaining_tasks} are remaining tasks in this project."
notification_type = "publish_project"
annotators_ids = [a.get("id") for a in annotators]
reviewers_ids = [r.get("id") for r in reviewers]
super_checkers_ids = [s.get("id") for s in super_checkers]
project_workspace = project.workspace_id
project_workspace_managers = project_workspace.managers.all()
project_workspace_managers_ids = [p.id for p in project_workspace_managers]
users_ids = set(
annotators_ids
+ reviewers_ids
+ super_checkers_ids
+ project_workspace_managers_ids
)
try:
project.save()
createNotification(title, notification_type, annotators_ids,reviewers_ids,super_checkers_ids)
createNotification(
request, title, project.id, notification_type, list(users_ids)
)
ret_dict = {"message": "This project is published"}
ret_status = status.HTTP_200_OK
except Exception as e:
Expand Down
Loading