416
base/announcement.py
Normal file
416
base/announcement.py
Normal file
@@ -0,0 +1,416 @@
|
||||
"""
|
||||
Module for managing announcements, including creation, updates, comments, and views.
|
||||
"""
|
||||
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from base.forms import AnnouncementCommentForm, AnnouncementForm
|
||||
from base.methods import closest_numbers, filter_own_records
|
||||
from base.models import (
|
||||
Announcement,
|
||||
AnnouncementComment,
|
||||
AnnouncementExpire,
|
||||
AnnouncementView,
|
||||
Attachment,
|
||||
)
|
||||
from employee.models import Employee
|
||||
from horilla.decorators import hx_request_required, login_required, permission_required
|
||||
from notifications.signals import notify
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def announcement_list(request):
|
||||
"""
|
||||
Renders a list of announcements for the authenticated user.
|
||||
|
||||
This view fetches all announcements and updates their expiration dates if not already set.
|
||||
It filters announcements based on the user's permissions and whether the announcements
|
||||
are still valid (not expired). Additionally, it checks if the user has viewed each announcement.
|
||||
"""
|
||||
general_expire_date = (
|
||||
AnnouncementExpire.objects.values_list("days", flat=True).first() or 30
|
||||
)
|
||||
announcements = Announcement.objects.all()
|
||||
announcements_to_update = []
|
||||
|
||||
for announcement in announcements.filter(expire_date__isnull=True):
|
||||
announcement.expire_date = announcement.created_at + timedelta(
|
||||
days=general_expire_date
|
||||
)
|
||||
announcements_to_update.append(announcement)
|
||||
|
||||
if announcements_to_update:
|
||||
Announcement.objects.bulk_update(announcements_to_update, ["expire_date"])
|
||||
|
||||
has_view_permission = request.user.has_perm("base.view_announcement")
|
||||
announcements = announcements.filter(expire_date__gte=datetime.today().date())
|
||||
announcement_items = (
|
||||
announcements
|
||||
if has_view_permission
|
||||
else announcements.filter(
|
||||
Q(employees=request.user.employee_get) | Q(employees__isnull=True)
|
||||
)
|
||||
)
|
||||
|
||||
filtered_announcements = announcement_items.prefetch_related(
|
||||
"announcementview_set"
|
||||
).order_by("-created_at")
|
||||
for announcement in filtered_announcements:
|
||||
announcement.has_viewed = announcement.announcementview_set.filter(
|
||||
user=request.user, viewed=True
|
||||
).exists()
|
||||
instance_ids = json.dumps([instance.id for instance in filtered_announcements])
|
||||
context = {
|
||||
"announcements": filtered_announcements,
|
||||
"general_expire_date": general_expire_date,
|
||||
"instance_ids": instance_ids,
|
||||
}
|
||||
return render(request, "announcement/announcements_list.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def create_announcement(request):
|
||||
"""
|
||||
Create a new announcement and notify relevant users.
|
||||
"""
|
||||
form = AnnouncementForm()
|
||||
if request.method == "POST":
|
||||
form = AnnouncementForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
announcement, attachment_ids = form.save(commit=False)
|
||||
announcement.save()
|
||||
announcement.attachments.set(attachment_ids)
|
||||
|
||||
employees = form.cleaned_data["employees"]
|
||||
departments = form.cleaned_data["department"]
|
||||
job_positions = form.cleaned_data["job_position"]
|
||||
company = form.cleaned_data["company_id"]
|
||||
|
||||
announcement.department.set(departments)
|
||||
announcement.job_position.set(job_positions)
|
||||
announcement.company_id.set(company)
|
||||
|
||||
dept_ids = departments.values_list("id", flat=True)
|
||||
job_ids = job_positions.values_list("id", flat=True)
|
||||
|
||||
employees_from_dept = Employee.objects.filter(
|
||||
employee_work_info__department_id__in=dept_ids
|
||||
)
|
||||
employees_from_job = Employee.objects.filter(
|
||||
employee_work_info__job_position_id__in=job_ids
|
||||
)
|
||||
|
||||
all_employees = (
|
||||
employees | employees_from_dept | employees_from_job
|
||||
).distinct()
|
||||
announcement.employees.add(*all_employees)
|
||||
|
||||
all_emps = employees_from_dept | employees_from_job | employees
|
||||
user_map = User.objects.filter(employee_get__in=all_emps).distinct()
|
||||
|
||||
dept_emp_ids = set(employees_from_dept.values_list("id", flat=True))
|
||||
job_emp_ids = set(employees_from_job.values_list("id", flat=True))
|
||||
direct_emp_ids = set(employees.values_list("id", flat=True))
|
||||
|
||||
notified_ids = dept_emp_ids.union(job_emp_ids)
|
||||
direct_only_ids = direct_emp_ids - notified_ids
|
||||
|
||||
sender = request.user.employee_get
|
||||
|
||||
def send_notification(users, verb):
|
||||
if users.exists():
|
||||
notify.send(
|
||||
sender,
|
||||
recipient=users,
|
||||
verb=verb,
|
||||
verb_ar="لقد تم ذكرك في إعلان.",
|
||||
verb_de="Sie wurden in einer Ankündigung erwähnt.",
|
||||
verb_es="Has sido mencionado en un anuncio.",
|
||||
verb_fr="Vous avez été mentionné dans une annonce.",
|
||||
redirect="/",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
|
||||
send_notification(
|
||||
user_map.filter(employee_get__id__in=dept_emp_ids),
|
||||
_("Your department was mentioned in an announcement."),
|
||||
)
|
||||
send_notification(
|
||||
user_map.filter(employee_get__id__in=job_emp_ids),
|
||||
_("Your job position was mentioned in an announcement."),
|
||||
)
|
||||
send_notification(
|
||||
user_map.filter(employee_get__id__in=direct_only_ids),
|
||||
_("You have been mentioned in an announcement."),
|
||||
)
|
||||
|
||||
messages.success(request, _("Announcement created successfully."))
|
||||
form = AnnouncementForm() # Reset the form
|
||||
|
||||
return render(request, "announcement/announcement_form.html", {"form": form})
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def delete_announcement(request, anoun_id):
|
||||
"""
|
||||
This method is used to delete announcements.
|
||||
"""
|
||||
announcement = Announcement.find(anoun_id)
|
||||
if announcement:
|
||||
announcement.delete()
|
||||
messages.success(request, _("Announcement deleted successfully."))
|
||||
|
||||
instance_ids = request.GET.get("instance_ids")
|
||||
instance_ids_list = json.loads(instance_ids)
|
||||
__, next_instance_id = (
|
||||
closest_numbers(instance_ids_list, anoun_id)
|
||||
if instance_ids_list
|
||||
else (None, None)
|
||||
)
|
||||
|
||||
if anoun_id in instance_ids_list:
|
||||
instance_ids_list.remove(anoun_id)
|
||||
|
||||
if next_instance_id and next_instance_id != anoun_id:
|
||||
url = reverse("announcement-single-view", kwargs={"anoun_id": next_instance_id})
|
||||
return redirect(f"{url}?instance_ids={json.dumps(instance_ids_list)}")
|
||||
return redirect(announcement_single_view)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def update_announcement(request, anoun_id):
|
||||
"""
|
||||
This method renders form and template to update Announcement
|
||||
"""
|
||||
|
||||
announcement = Announcement.objects.get(id=anoun_id)
|
||||
form = AnnouncementForm(instance=announcement)
|
||||
existing_attachments = list(announcement.attachments.all())
|
||||
|
||||
instance_ids = request.GET.get("instance_ids")
|
||||
|
||||
if request.method == "POST":
|
||||
form = AnnouncementForm(request.POST, request.FILES, instance=announcement)
|
||||
if form.is_valid():
|
||||
anou, attachment_ids = form.save(commit=False)
|
||||
anou.save()
|
||||
if attachment_ids:
|
||||
all_attachments = set(existing_attachments) | set(
|
||||
Attachment.objects.filter(id__in=attachment_ids)
|
||||
)
|
||||
anou.attachments.set(all_attachments)
|
||||
else:
|
||||
anou.attachments.set(existing_attachments)
|
||||
|
||||
employees = form.cleaned_data["employees"]
|
||||
departments = form.cleaned_data["department"]
|
||||
job_positions = form.cleaned_data["job_position"]
|
||||
company = form.cleaned_data["company_id"]
|
||||
anou.department.set(departments)
|
||||
anou.job_position.set(job_positions)
|
||||
anou.company_id.set(company)
|
||||
messages.success(request, _("Announcement updated successfully."))
|
||||
|
||||
emp_dep = User.objects.filter(
|
||||
employee_get__employee_work_info__department_id__in=departments
|
||||
)
|
||||
emp_jobs = User.objects.filter(
|
||||
employee_get__employee_work_info__job_position_id__in=job_positions
|
||||
)
|
||||
employees = employees | Employee.objects.filter(
|
||||
employee_work_info__department_id__in=departments
|
||||
)
|
||||
employees = employees | Employee.objects.filter(
|
||||
employee_work_info__job_position_id__in=job_positions
|
||||
)
|
||||
anou.employees.add(*employees)
|
||||
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=emp_dep,
|
||||
verb="Your department was mentioned in a post.",
|
||||
verb_ar="تم ذكر قسمك في منشور.",
|
||||
verb_de="Ihr Abteilung wurde in einem Beitrag erwähnt.",
|
||||
verb_es="Tu departamento fue mencionado en una publicación.",
|
||||
verb_fr="Votre département a été mentionné dans un post.",
|
||||
redirect="/",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=emp_jobs,
|
||||
verb="Your job position was mentioned in a post.",
|
||||
verb_ar="تم ذكر وظيفتك في منشور.",
|
||||
verb_de="Ihre Arbeitsposition wurde in einem Beitrag erwähnt.",
|
||||
verb_es="Tu puesto de trabajo fue mencionado en una publicación.",
|
||||
verb_fr="Votre poste de travail a été mentionné dans un post.",
|
||||
redirect="/",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
"announcement/announcement_update_form.html",
|
||||
{
|
||||
"form": form,
|
||||
"instance_ids": instance_ids,
|
||||
"hx_target": request.META.get("HTTP_HX_TARGET", ""),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def remove_announcement_file(request, obj_id, attachment_id):
|
||||
announcement = get_object_or_404(Announcement, id=obj_id)
|
||||
attachment = get_object_or_404(Attachment, id=attachment_id)
|
||||
|
||||
announcement.attachments.remove(attachment)
|
||||
messages.success(request, _("The file has been successfully deleted."))
|
||||
return HttpResponse("<script>reloadMessage();</script>")
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def create_announcement_comment(request, anoun_id):
|
||||
"""
|
||||
This method renders form and template to create Announcement comments
|
||||
"""
|
||||
anoun = Announcement.objects.filter(id=anoun_id).first()
|
||||
emp = request.user.employee_get
|
||||
form = AnnouncementCommentForm(
|
||||
initial={"employee_id": emp.id, "request_id": anoun_id}
|
||||
)
|
||||
comments = AnnouncementComment.objects.filter(announcement_id=anoun_id)
|
||||
commentators = []
|
||||
if comments:
|
||||
for i in comments:
|
||||
commentators.append(i.employee_id.employee_user_id)
|
||||
unique_users = list(set(commentators))
|
||||
|
||||
if request.method == "POST":
|
||||
form = AnnouncementCommentForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.instance.employee_id = emp
|
||||
form.instance.announcement_id = anoun
|
||||
form.save()
|
||||
form = AnnouncementCommentForm(
|
||||
initial={"employee_id": emp.id, "request_id": anoun_id}
|
||||
)
|
||||
messages.success(request, _("You commented a post."))
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=unique_users,
|
||||
verb=f"Comment under the announcement {anoun.title}.",
|
||||
verb_ar=f"تعليق تحت الإعلان {anoun.title}.",
|
||||
verb_de=f"Kommentar unter der Ankündigung {anoun.title}.",
|
||||
verb_es=f"Comentario bajo el anuncio {anoun.title}.",
|
||||
verb_fr=f"Commentaire sous l'annonce {anoun.title}.",
|
||||
redirect="/",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
return redirect("announcement-view-comment", anoun_id=anoun_id)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"announcement/comment_view.html",
|
||||
{"form": form, "request_id": anoun_id},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def comment_view(request, anoun_id):
|
||||
"""
|
||||
This method is used to view all comments in the announcements
|
||||
"""
|
||||
announcement = Announcement.objects.get(id=anoun_id)
|
||||
comments = AnnouncementComment.objects.filter(announcement_id=anoun_id).order_by(
|
||||
"-created_at"
|
||||
)
|
||||
if not announcement.public_comments:
|
||||
comments = filter_own_records(
|
||||
request, comments, "base.view_announcementcomment"
|
||||
)
|
||||
no_comments = not comments.exists()
|
||||
|
||||
return render(
|
||||
request,
|
||||
"announcement/comment_view.html",
|
||||
{
|
||||
"comments": comments,
|
||||
"no_comments": no_comments,
|
||||
"request_id": anoun_id,
|
||||
"announcement": announcement,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def delete_announcement_comment(request, comment_id):
|
||||
"""
|
||||
This method is used to delete announcement comments
|
||||
"""
|
||||
comment = AnnouncementComment.objects.get(id=comment_id)
|
||||
comment.delete()
|
||||
messages.success(request, _("Comment deleted successfully!"))
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def announcement_single_view(request, anoun_id=None):
|
||||
"""
|
||||
This method is used to render single announcements.
|
||||
"""
|
||||
announcement_instance = Announcement.find(anoun_id)
|
||||
instance_ids = request.GET.get("instance_ids")
|
||||
instance_ids_list = json.loads(instance_ids) if instance_ids else []
|
||||
previous_instance_id, next_instance_id = (
|
||||
closest_numbers(instance_ids_list, anoun_id)
|
||||
if instance_ids_list
|
||||
else (None, None)
|
||||
)
|
||||
if announcement_instance:
|
||||
announcement_view_obj, _ = AnnouncementView.objects.get_or_create(
|
||||
user=request.user, announcement=announcement_instance
|
||||
)
|
||||
announcement_view_obj.viewed = True
|
||||
announcement_view_obj.save()
|
||||
|
||||
context = {
|
||||
"announcement": announcement_instance,
|
||||
"instance_ids": instance_ids,
|
||||
"previous_instance_id": previous_instance_id,
|
||||
"next_instance_id": next_instance_id,
|
||||
}
|
||||
|
||||
return render(request, "announcement/announcement_one.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
@permission_required("base.view_announcement")
|
||||
def viewed_by(request):
|
||||
"""
|
||||
This method is used to view the employees
|
||||
"""
|
||||
announcement_id = request.GET.get("announcement_id")
|
||||
viewed_users = AnnouncementView.objects.filter(
|
||||
announcement_id__id=announcement_id, viewed=True
|
||||
)
|
||||
return render(request, "announcement/viewed_by.html", {"viewed_by": viewed_users})
|
||||
Reference in New Issue
Block a user