diff --git a/base/admin.py b/base/admin.py index 308437356..f71922c51 100644 --- a/base/admin.py +++ b/base/admin.py @@ -7,6 +7,8 @@ from django.contrib import admin from simple_history.admin import SimpleHistoryAdmin from base.models import ( + Announcement, + Attachment, Company, Department, DynamicEmailConfiguration, @@ -53,4 +55,10 @@ admin.site.register(MultipleApprovalManagers) admin.site.register(ShiftrequestComment) admin.site.register(WorktyperequestComment) admin.site.register(DynamicPagination) +admin.site.register(Announcement) +admin.site.register(Attachment) + + + + diff --git a/base/announcement.py b/base/announcement.py new file mode 100644 index 000000000..c83914289 --- /dev/null +++ b/base/announcement.py @@ -0,0 +1,251 @@ +from django.http import HttpResponse, JsonResponse +from django.shortcuts import redirect, render +from base.forms import AnnouncementForm, AnnouncementcommentForm +from base.models import Announcement, AnnouncementComment +from employee.models import EmployeeWorkInformation +from horilla.decorators import login_required +from django.contrib import messages +from django.utils.translation import gettext_lazy as _ +from notifications.signals import notify +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger + + + +@login_required +def announcement_view(request): + + """ + This method is used to render all announcemnts. + """ + + announcement_list = Announcement.objects.all().order_by('-created_on') + + # Set the number of items per page + items_per_page = 10 + + paginator = Paginator(announcement_list, items_per_page) + + page = request.GET.get('page') + try: + announcements = paginator.page(page) + except PageNotAnInteger: + # If the page is not an integer, deliver the first page. + announcements = paginator.page(1) + except EmptyPage: + # If the page is out of range (e.g., 9999), deliver the last page of results. + announcements = paginator.page(paginator.num_pages) + + return render(request, "announcement/announcement.html", {'announcements': announcements}) + + + +@login_required +def create_announcement(request): + + """ + This method renders form and template to update Announcement + """ + + form = AnnouncementForm() + if request.method == "POST": + form = AnnouncementForm(request.POST, request.FILES) + if form.is_valid(): + anou,attachment_ids = form.save(commit=False) + anou.save() + anou.attachments.set(attachment_ids) + departments = form.cleaned_data["department"] + job_positions = form.cleaned_data["job_position"] + anou.department.set(departments) + anou.job_position.set(job_positions) + messages.success(request, _("Announcement created successfully.")) + + depar = [] + jobs = [] + emp_dep = [] + emp_jobs = [] + for i in departments: + depar.append(i.id) + for i in job_positions: + jobs.append(i.id) + + for i in depar: + emp = EmployeeWorkInformation.objects.filter(department_id = i) + for i in emp: + name = i.employee_id + emp_dep.append(name.employee_user_id) + + for i in jobs: + emp = EmployeeWorkInformation.objects.filter(job_position_id = i) + for i in emp: + name = i.employee_id + emp_jobs.append(name.employee_user_id) + + 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="/announcement", + 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="/announcement", + icon="chatbox-ellipses", + ) + + response = render( + request, "announcement/announcement_form.html", {"form": form} + ) + return HttpResponse( + response.content.decode("utf-8") + "" + ) + return render(request, "announcement/announcement_form.html", {"form": form}) + + +@login_required +def delete_announcement(request, anoun_id): + + """ + This method is used to delete announcemnts. + """ + + announcement = Announcement.objects.filter(id=anoun_id) + announcement.delete() + messages.success(request, _("Announcement deleted successfully.")) + return redirect(announcement_view) + + +@login_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) + + if request.method == "POST": + form = AnnouncementForm(request.POST, request.FILES, instance=announcement) + if form.is_valid(): + anou,attachment_ids = form.save(commit=False) + announcement = anou.save() + anou.attachments.set(attachment_ids) + departments = form.cleaned_data["department"] + job_positions = form.cleaned_data["job_position"] + anou.department.set(departments) + anou.job_position.set(job_positions) + messages.success(request, _("Announcement updated successfully.")) + + depar = [] + jobs = [] + emp_dep = [] + emp_jobs = [] + for i in departments: + depar.append(i.id) + for i in job_positions: + jobs.append(i.id) + + for i in depar: + emp = EmployeeWorkInformation.objects.filter(department_id = i) + for i in emp: + name = i.employee_id + emp_dep.append(name.employee_user_id) + + for i in jobs: + emp = EmployeeWorkInformation.objects.filter(job_position_id = i) + for i in emp: + name = i.employee_id + emp_jobs.append(name.employee_user_id) + + 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="/announcement", + 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="/announcement", + icon="chatbox-ellipses", + ) + + response = render( + request, "announcement/announcement_update_form.html", {"form": form} + ) + return HttpResponse( + response.content.decode("utf-8") + "" + ) + return render(request, "announcement/announcement_update_form.html", {"form": form}) + + +@login_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} + ) + + 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.")) + return HttpResponse("") + return render( + request, + "announcement/comment_form.html", + {"form": form, "request_id": anoun_id}, + ) + + +@login_required +def comment_view(request, anoun_id): + """ + This method is used to view all comments in the announcements + """ + comments = AnnouncementComment.objects.filter(announcement_id=anoun_id).order_by( + "-created_at" + ) + no_comments = False + if not comments.exists(): + no_comments = True + + return render( + request, + "announcement/comment_view.html", + {"comments": comments, "no_comments": no_comments}, + ) + diff --git a/base/forms.py b/base/forms.py index 5ce61b8d3..b9404fe21 100644 --- a/base/forms.py +++ b/base/forms.py @@ -5,6 +5,7 @@ This module is used to register forms for base module """ import calendar import os +from typing import Any import uuid import datetime from datetime import timedelta @@ -19,6 +20,9 @@ from django.template.loader import render_to_string from employee.filters import EmployeeFilter from employee.models import Employee, EmployeeTag from base.models import ( + Announcement, + AnnouncementComment, + Attachment, Company, Department, DynamicEmailConfiguration, @@ -1617,4 +1621,78 @@ class DynamicPaginationForm(ModelForm): fields = "__all__" exclude = ('user_id',) - \ No newline at end of file + + +class MultipleFileInput(forms.ClearableFileInput): + allow_multiple_selected = True + + +class MultipleFileField(forms.FileField): + def __init__(self, *args, **kwargs): + kwargs.setdefault("widget", MultipleFileInput()) + super().__init__(*args, **kwargs) + + def clean(self, data, initial=None): + single_file_clean = super().clean + if isinstance(data, (list, tuple)): + result = [single_file_clean(d, initial) for d in data] + else: + result = [single_file_clean(data, initial),] + return result[0] if result else None + + +class AnnouncementForm(ModelForm): + """ + Announcement Form + """ + + class Meta: + """ + Meta class for additional options + """ + + model = Announcement + fields = '__all__' + excluded_fields = ['created_on'] + widgets = { + "description": forms.Textarea(attrs={"data-summernote": ""}), + } + + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["attachments"] = MultipleFileField(label="Attachments ") + self.fields["attachments"].required=False + + def save(self, commit: bool = ...) -> Any: + attachement = [] + multiple_attachment_ids = [] + attachements = None + if self.files.getlist("attachments"): + attachements = self.files.getlist("attachments") + self.instance.attachement = attachements[0] + multiple_attachment_ids = [] + + for attachement in attachements: + file_instance = Attachment() + file_instance.file = attachement + file_instance.save() + multiple_attachment_ids.append(file_instance.pk) + instance = super().save(commit) + if commit: + instance.attachements.add(*multiple_attachment_ids) + return instance, multiple_attachment_ids + +class AnnouncementcommentForm(ModelForm): + """ + Announcement comment form + """ + + class Meta: + """ + Meta class for additional options + """ + + model = AnnouncementComment + fields = ('comment',) + diff --git a/base/models.py b/base/models.py index 3a3e0db8f..cb2b67c5f 100644 --- a/base/models.py +++ b/base/models.py @@ -1159,4 +1159,44 @@ class DynamicPagination(models.Model): super().save(*args, **kwargs) def __str__(self): return (f"{self.user_id}|{self.pagination}") - \ No newline at end of file + + +class Attachment(models.Model): + """ + Attachment model for multiple attachments in announcemnts. + """ + file = models.FileField(upload_to='attachments/') + + def __str__(self): + return self.file.name + +class Announcement(models.Model): + + """ + Anonuncement Model for stroing all announcements. + """ + title = models.CharField(max_length=30) + description = models.TextField(null=True) + attachments = models.ManyToManyField(Attachment, related_name='announcement_attachments', blank=True) + created_on = models.DateTimeField(auto_now_add=True) + department = models.ManyToManyField(Department, blank=True) + job_position = models.ManyToManyField(JobPosition, blank=True) + + def __str__(self): + return self.title + + +class AnnouncementComment(models.Model): + """ + AnnouncementComment Model + """ + from employee.models import Employee + + announcement_id = models.ForeignKey(Announcement, on_delete=models.CASCADE) + employee_id = models.ForeignKey(Employee, on_delete=models.CASCADE) + comment = models.TextField(null=True, verbose_name=_("Comment")) + created_at = models.DateTimeField( + auto_now_add=True, + verbose_name=_("Created At"), + null=True, + ) diff --git a/base/templates/announcement/announcement.html b/base/templates/announcement/announcement.html new file mode 100644 index 000000000..ca43ab082 --- /dev/null +++ b/base/templates/announcement/announcement.html @@ -0,0 +1,512 @@ +{% extends "index.html" %} +{% load i18n %} +{% load static %} +{% load basefilters %} +{% block content %} + +{% comment %} + + + +{% if perms.announcemnt.add_announcemnt or request.user|is_reportingmanager %} +
{{ anoun.description|safe }}
+{{ anoun.description|safe }}
+ + {% if anoun.department.all %} +
+