[ADD] ACCESSIBILITY: Add employee accessibility app for handling employees permissions and accessibility
This commit is contained in:
0
accessibility/__init__.py
Normal file
0
accessibility/__init__.py
Normal file
11
accessibility/accessibility.py
Normal file
11
accessibility/accessibility.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
accessibility/accessibility.py
|
||||
"""
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
ACCESSBILITY_FEATURE = [
|
||||
("employee_view", _("Default Employee View")),
|
||||
("employee_detailed_view", _("Default Employee Detailed View")),
|
||||
]
|
||||
3
accessibility/admin.py
Normal file
3
accessibility/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
15
accessibility/apps.py
Normal file
15
accessibility/apps.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AccessibilityConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "accessibility"
|
||||
|
||||
def ready(self) -> None:
|
||||
from horilla.urls import urlpatterns, include, path
|
||||
from accessibility import signals
|
||||
|
||||
urlpatterns.append(
|
||||
path("", include("accessibility.urls")),
|
||||
)
|
||||
return super().ready()
|
||||
51
accessibility/decorators.py
Normal file
51
accessibility/decorators.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
employee/decorators.py
|
||||
"""
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.shortcuts import redirect
|
||||
from accessibility.methods import check_is_accessibile
|
||||
from base.decorators import decorator_with_arguments
|
||||
|
||||
|
||||
@decorator_with_arguments
|
||||
def enter_if_accessible(function, feature, perm=None, method=None):
|
||||
"""
|
||||
accessiblie check decorator
|
||||
"""
|
||||
|
||||
def check_accessible(request, *args, **kwargs):
|
||||
"""
|
||||
Check accessible
|
||||
"""
|
||||
path = "/"
|
||||
referrer = request.META.get("HTTP_REFERER")
|
||||
if referrer and request.path not in referrer:
|
||||
path = request.META["HTTP_REFERER"]
|
||||
accessible = False
|
||||
cache_key = request.session.session_key + "accessibility_filter"
|
||||
employee = getattr(request.user, "employee_get")
|
||||
if employee:
|
||||
accessible = check_is_accessibile(feature, cache_key, employee)
|
||||
has_perm = True
|
||||
if perm:
|
||||
has_perm = request.user.has_perm(perm)
|
||||
|
||||
if accessible or has_perm or method(request):
|
||||
return function(request, *args, **kwargs)
|
||||
key = "HTTP_HX_REQUEST"
|
||||
keys = request.META.keys()
|
||||
messages.info(request, _("You dont have access to the feature"))
|
||||
if key in keys:
|
||||
return HttpResponse(
|
||||
f"""
|
||||
<script>
|
||||
window.location.href="{referrer}"
|
||||
</script>
|
||||
"""
|
||||
)
|
||||
return redirect(path)
|
||||
|
||||
return check_accessible
|
||||
102
accessibility/filters.py
Normal file
102
accessibility/filters.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
accessibility/filters.py
|
||||
"""
|
||||
|
||||
from functools import reduce
|
||||
from django.utils.translation import gettext as _
|
||||
from django.db.models import Q
|
||||
from django.template.loader import render_to_string
|
||||
import django_filters
|
||||
from horilla.filters import HorillaFilterSet
|
||||
from horilla.horilla_middlewares import _thread_locals
|
||||
from employee.models import Employee
|
||||
|
||||
|
||||
def _filter_form_structured(self):
|
||||
"""
|
||||
Render the form fields as HTML table rows with Bootstrap styling.
|
||||
"""
|
||||
request = getattr(_thread_locals, "request", None)
|
||||
context = {
|
||||
"form": self,
|
||||
"request": request,
|
||||
}
|
||||
table_html = render_to_string("accessibility/filter_form_body.html", context)
|
||||
return table_html
|
||||
|
||||
|
||||
class AccessibilityFilter(HorillaFilterSet):
|
||||
"""
|
||||
Accessibility Filter with dynamic OR logic between fields
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form.structured = _filter_form_structured(self.form)
|
||||
|
||||
pk = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Employee.objects.all(),
|
||||
field_name="pk",
|
||||
lookup_expr="in",
|
||||
label=_("Employee"),
|
||||
)
|
||||
|
||||
verbose_name = {
|
||||
"employee_work_info__job_position_id": _("Job Position"),
|
||||
"employee_work_info__department_id": _("Department"),
|
||||
"employee_work_info__work_type_id": _("Work Type"),
|
||||
"employee_work_info__employee_type_id": _("Employee Type"),
|
||||
"employee_work_info__job_role_id": _("Job Role"),
|
||||
"employee_work_info__company_id": _("Company"),
|
||||
"employee_work_info__shift_id": _("Shift"),
|
||||
"employee_work_info__tags": _("Tags"),
|
||||
"employee_user_id__groups": _("Groups"),
|
||||
"employee_user_id__user_permissions": _("Permissions"),
|
||||
}
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Meta class for additional options
|
||||
"""
|
||||
|
||||
model = Employee
|
||||
fields = [
|
||||
"pk",
|
||||
"employee_work_info__job_position_id",
|
||||
"employee_work_info__department_id",
|
||||
"employee_work_info__work_type_id",
|
||||
"employee_work_info__employee_type_id",
|
||||
"employee_work_info__job_role_id",
|
||||
"employee_work_info__company_id",
|
||||
"employee_work_info__shift_id",
|
||||
"employee_work_info__tags",
|
||||
"employee_user_id__groups",
|
||||
"employee_user_id__user_permissions",
|
||||
]
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
"""
|
||||
Dynamically apply OR condition between all specified fields
|
||||
"""
|
||||
or_conditions = []
|
||||
|
||||
# Get the filter fields from Meta class
|
||||
for field in self.Meta.fields:
|
||||
field_value = self.data.get(field)
|
||||
if field_value:
|
||||
if isinstance(field_value, list) and len(field_value) == 1:
|
||||
field_value = field_value[0]
|
||||
|
||||
if "__" in field:
|
||||
or_conditions.append(Q(**{f"{field}__id__in": field_value}))
|
||||
else:
|
||||
if isinstance(field_value, list):
|
||||
or_conditions.append(Q(**{f"{field}__in": field_value}))
|
||||
else:
|
||||
or_conditions.append(Q(**{f"{field}__in": [field_value]}))
|
||||
|
||||
|
||||
if or_conditions:
|
||||
queryset = queryset.filter(reduce(lambda x, y: x | y, or_conditions))
|
||||
|
||||
return queryset
|
||||
30
accessibility/methods.py
Normal file
30
accessibility/methods.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
accessibility/methods.py
|
||||
"""
|
||||
|
||||
from django.core.cache import cache
|
||||
from horilla.horilla_middlewares import _thread_locals
|
||||
from accessibility.models import DefaultAccessibility
|
||||
from accessibility.filters import AccessibilityFilter
|
||||
|
||||
|
||||
def check_is_accessibile(feature, cache_key, employee):
|
||||
"""
|
||||
Method to check the employee is accessible for the feature or not
|
||||
"""
|
||||
if not employee:
|
||||
return False
|
||||
|
||||
accessibility = DefaultAccessibility.objects.filter(feature=feature).first()
|
||||
|
||||
if not feature or not accessibility:
|
||||
return True
|
||||
|
||||
data: dict = cache.get(cache_key, default={})
|
||||
if data and data.get(feature) is not None:
|
||||
return data.get(feature)
|
||||
|
||||
filter = accessibility.filter
|
||||
employees = AccessibilityFilter(data=filter).qs
|
||||
accessibile = employee in employees
|
||||
return accessibile
|
||||
49
accessibility/middlewares.py
Normal file
49
accessibility/middlewares.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
accessibility/middlewares.py
|
||||
"""
|
||||
|
||||
from django.core.cache import cache
|
||||
from accessibility.models import ACCESSBILITY_FEATURE
|
||||
from accessibility.methods import check_is_accessibile
|
||||
|
||||
ACCESSIBILITY_CACHE_USER_KEYS = {}
|
||||
|
||||
|
||||
def update_accessibility_cache(cache_key, request):
|
||||
"""
|
||||
Cache for get all the queryset
|
||||
"""
|
||||
feature_accessible = {}
|
||||
for accessibility, _display in ACCESSBILITY_FEATURE:
|
||||
feature_accessible[accessibility] = check_is_accessibile(
|
||||
accessibility, cache_key, getattr(request.user, "employee_get")
|
||||
)
|
||||
cache.set(cache_key, feature_accessible)
|
||||
|
||||
|
||||
class AccessibilityMiddleware:
|
||||
"""
|
||||
AccessibilityMiddleware
|
||||
"""
|
||||
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
session_key = request.session.session_key
|
||||
if session_key:
|
||||
cache_key = session_key + "accessibility_filter"
|
||||
exists_user_cache_key = ACCESSIBILITY_CACHE_USER_KEYS.get(
|
||||
request.user.id, []
|
||||
)
|
||||
if not exists_user_cache_key:
|
||||
ACCESSIBILITY_CACHE_USER_KEYS[request.user.id] = exists_user_cache_key
|
||||
if (
|
||||
session_key
|
||||
and getattr(request.user, "employee_get", None)
|
||||
and not cache.get(cache_key)
|
||||
):
|
||||
exists_user_cache_key.append(cache_key)
|
||||
update_accessibility_cache(cache_key, request)
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
0
accessibility/migrations/__init__.py
Normal file
0
accessibility/migrations/__init__.py
Normal file
16
accessibility/models.py
Normal file
16
accessibility/models.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
accessibility/models.py
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
from horilla.models import HorillaModel
|
||||
from accessibility.accessibility import ACCESSBILITY_FEATURE
|
||||
|
||||
|
||||
class DefaultAccessibility(HorillaModel):
|
||||
"""
|
||||
DefaultAccessibilityModel
|
||||
"""
|
||||
|
||||
feature = models.CharField(max_length=100, choices=ACCESSBILITY_FEATURE)
|
||||
filter = models.JSONField()
|
||||
67
accessibility/signals.py
Normal file
67
accessibility/signals.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
accessibility/signals.py
|
||||
"""
|
||||
|
||||
import threading
|
||||
from django.db.models.signals import post_save
|
||||
from django.core.cache import cache
|
||||
from django.dispatch import receiver
|
||||
from employee.models import EmployeeWorkInformation
|
||||
from accessibility.models import DefaultAccessibility
|
||||
from accessibility.middlewares import (
|
||||
ACCESSIBILITY_CACHE_USER_KEYS,
|
||||
)
|
||||
from horilla.signals import post_bulk_update
|
||||
|
||||
|
||||
def _clear_accessibility_cache():
|
||||
for _user_id, cache_keys in ACCESSIBILITY_CACHE_USER_KEYS.copy().items():
|
||||
for key in cache_keys:
|
||||
cache.delete(key)
|
||||
|
||||
|
||||
def _clear_bulk_employees_cache(queryset):
|
||||
for instance in queryset:
|
||||
cache_key = ACCESSIBILITY_CACHE_USER_KEYS.get(
|
||||
instance.employee_id.employee_user_id.id
|
||||
)
|
||||
if cache_key:
|
||||
cache.delete(cache_key)
|
||||
|
||||
|
||||
@receiver(post_save, sender=EmployeeWorkInformation)
|
||||
def monitor_employee_update(sender, instance, created, **kwargs):
|
||||
"""
|
||||
This method to track employee instance update
|
||||
"""
|
||||
|
||||
_sender = sender
|
||||
_created = created
|
||||
cache_keys = ACCESSIBILITY_CACHE_USER_KEYS.copy().get(
|
||||
instance.employee_id.employee_user_id.id, []
|
||||
)
|
||||
for key in cache_keys:
|
||||
cache.delete(key)
|
||||
|
||||
|
||||
@receiver(post_save, sender=DefaultAccessibility)
|
||||
def monitor_accessibility_update(sender, instance, created, **kwargs):
|
||||
"""
|
||||
This method is used to track accessibility updates
|
||||
"""
|
||||
_sender = sender
|
||||
_created = created
|
||||
_instance = instance
|
||||
thread = threading.Thread(target=_clear_accessibility_cache)
|
||||
thread.start()
|
||||
|
||||
|
||||
@receiver(post_bulk_update, sender=EmployeeWorkInformation)
|
||||
def monitor_employee_bulk_update(sender, queryset, *args, **kwargs):
|
||||
"""
|
||||
This method is used to track accessibility updates
|
||||
"""
|
||||
_sender = sender
|
||||
_queryset = queryset
|
||||
thread = threading.Thread(target=_clear_bulk_employees_cache(queryset))
|
||||
thread.start()
|
||||
146
accessibility/templates/accessibility/accessibility.html
Normal file
146
accessibility/templates/accessibility/accessibility.html
Normal file
@@ -0,0 +1,146 @@
|
||||
{% extends "settings.html" %}
|
||||
{% block settings %}
|
||||
{% load i18n %}
|
||||
<div id="response" hidden>
|
||||
</div>
|
||||
<div
|
||||
class="oh-inner-sidebar-content__header d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<h2 class="oh-inner-sidebar-content__title oh-label__info">
|
||||
{% trans "Default Accessibility" %}
|
||||
<span class="oh-info mr-2 mb-2" title="{% trans "Limit default view access to horilla feature" %}">
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
</div>
|
||||
<div class="oh-card" id="accessibilityContainer">
|
||||
<div class="oh-accordion-meta">
|
||||
{% for accessibility, display in accessibility %}
|
||||
<div class="oh-accordion-meta__item">
|
||||
<div class="oh-accordion-meta__header">
|
||||
<span class="oh-accordion-meta__title"
|
||||
>{{display}}</span
|
||||
>
|
||||
<div class="oh-accordion-meta__actions" onclick="event.stopPropagation()">
|
||||
<div class="oh-dropdown" x-data="{open: false}">
|
||||
<button
|
||||
class="oh-btn oh-stop-prop oh-accordion-meta__btn"
|
||||
@click="open = !open"
|
||||
@click.outside="open = false"
|
||||
>
|
||||
{% trans "Actions" %}
|
||||
<ion-icon
|
||||
class="ms-2 oh-accordion-meta__btn-icon"
|
||||
name="caret-down-outline"
|
||||
></ion-icon>
|
||||
</button>
|
||||
<div
|
||||
class="oh-dropdown__menu oh-dropdown__menu--right"
|
||||
x-show="open"
|
||||
>
|
||||
<ul class="oh-dropdown__items">
|
||||
{% comment %} <li class="oh-dropdown__item">
|
||||
<a href="#" class="oh-dropdown__link">Archive</a>
|
||||
</li> {% endcomment %}
|
||||
<li class="oh-dropdown__item">
|
||||
<a
|
||||
href="#"
|
||||
class="oh-dropdown__link oh-dropdown__link--danger"
|
||||
onclick="
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: `{% trans "You won't be able to revert this!" %}`,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '{% trans 'Yes' %}, {% trans 'Clear it' %}!'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$('#{{accessibility}}_body select').val('')
|
||||
$('#{{accessibility}}_body').find('input[type=submit]').click()
|
||||
$('#{{accessibility}}_body select').parent().find('span').remove()
|
||||
$('#{{accessibility}}_body select').select2()
|
||||
}
|
||||
});
|
||||
|
||||
"
|
||||
>{% trans "Clear Filter" %}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-accordion-meta__body d-none" id="{{accessibility}}_body">
|
||||
<form hx-post="" hx-target="#response" hx-swap="afterend">
|
||||
<input hidden type="text" name="feature" value="{{accessibility}}">
|
||||
{{accessibility_filter.form.structured}}
|
||||
<input hidden type="submit" value="submit">
|
||||
</form>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
setTimeout(() => {
|
||||
$.ajax({
|
||||
url: "{% url 'get-initial-accessibility-data' %}?feature={{accessibility}}",
|
||||
success: function (response) {
|
||||
for (let key in response) {
|
||||
if (response.hasOwnProperty(key)) {
|
||||
let values = response[key];
|
||||
let field = document.querySelector(`#{{accessibility}}_body [name="${key}"]`);
|
||||
|
||||
if (field) {
|
||||
// Handle select fields
|
||||
if (field.tagName === 'SELECT') {
|
||||
// Check if it's a multiple select
|
||||
if (field.multiple) {
|
||||
// Loop through the options and set selected if the value matches
|
||||
for (let option of field.options) {
|
||||
option.selected = values.includes(option.value);
|
||||
}
|
||||
} else {
|
||||
// For single select, set the value
|
||||
field.value = values[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
select = $("#accessibilityContainer #{{accessibility}}_body").find("select")
|
||||
select.parent().find('span').remove()
|
||||
select.select2()
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Save the filter form while change the filter form
|
||||
$("#accessibilityContainer select").change(function (e) {
|
||||
$(this).parent().closest("form").find("input[type=submit]").click();
|
||||
});
|
||||
$(document).mouseup(function(e) {
|
||||
var container = $('.select2.select2-container');
|
||||
if (!container.is(e.target) && container.has(e.target).length === 0) {
|
||||
setTimeout(() => {
|
||||
$(".select2-container.select2-container--default.select2-container--open").removeClass("select2-container--open")
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
const items = document.querySelectorAll("#accessibilityContainer select");
|
||||
items.forEach((item, index) => {
|
||||
item.id = `select-${index + 1}`;
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock settings %}
|
||||
22
accessibility/templates/accessibility/filter_form_body.html
Normal file
22
accessibility/templates/accessibility/filter_form_body.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% load widget_tweaks %} {% load i18n %}
|
||||
{% load generic_template_filters %}
|
||||
<div class="row" style="padding-right: 20px; padding-right: 10px;">
|
||||
<div class="col-12" style="padding-right: 20px !important;">{{ form.non_field_errors }}</div>
|
||||
{% for field in form.visible_fields %}
|
||||
<div class="col-12 col-md-{{ field|col }}" id="id_{{ field.name }}_parent_div" style="padding-right: 0;">
|
||||
<div class="oh-label__info" for="id_{{ field.name }}">
|
||||
<label class="oh-label {% if field.field.required %} required-star{% endif %}" for="id_{{ field.name }}"><b>{% trans field.label %}</b></label>
|
||||
{% if field.help_text != '' %}
|
||||
<span class="oh-info mr-2" title="{{ field.help_text|safe }}"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if field.field.widget.input_type == 'checkbox' %}
|
||||
<div class="oh-switch" style="width: 30px">{{ field|add_class:'oh-switch__checkbox' }}</div>
|
||||
{% else %}
|
||||
<div id="dynamic_field_{{ field.name }}">{{ field|add_class:'form-control' }}
|
||||
{{ field.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
3
accessibility/tests.py
Normal file
3
accessibility/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
20
accessibility/urls.py
Normal file
20
accessibility/urls.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
accessibility/urls.py
|
||||
"""
|
||||
|
||||
from django.urls import path
|
||||
from accessibility import views as accessibility
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"user-accessibility",
|
||||
accessibility.user_accessibility,
|
||||
name="user-accessibility",
|
||||
),
|
||||
path(
|
||||
"get-initial-accessibility-data",
|
||||
accessibility.get_accessibility_data,
|
||||
name="get-initial-accessibility-data",
|
||||
),
|
||||
]
|
||||
58
accessibility/views.py
Normal file
58
accessibility/views.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
employee/accessibility.py
|
||||
|
||||
Employee accessibility related methods and functionalites
|
||||
"""
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from horilla.decorators import login_required, permission_required
|
||||
from accessibility.filters import AccessibilityFilter
|
||||
from accessibility.models import DefaultAccessibility
|
||||
from accessibility.accessibility import ACCESSBILITY_FEATURE
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("auth.change_permission")
|
||||
def user_accessibility(request):
|
||||
"""
|
||||
User accessibility method
|
||||
"""
|
||||
if request.POST:
|
||||
feature = request.POST["feature"]
|
||||
accessibility = DefaultAccessibility.objects.filter(feature=feature).first()
|
||||
accessibility = accessibility if accessibility else DefaultAccessibility()
|
||||
accessibility.feature = feature
|
||||
accessibility.filter = dict(request.POST)
|
||||
accessibility.save()
|
||||
if len(request.POST.keys()) > 1:
|
||||
messages.success(request, _("Accessibility filter saved"))
|
||||
else:
|
||||
messages.info(request, _("All filter cleared"))
|
||||
|
||||
return HttpResponse("<script>$('#reloadMessagesButton').click()</script>")
|
||||
|
||||
accessibility_filter = AccessibilityFilter()
|
||||
return render(
|
||||
request,
|
||||
"accessibility/accessibility.html",
|
||||
{
|
||||
"accessibility": ACCESSBILITY_FEATURE,
|
||||
"accessibility_filter": accessibility_filter,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("auth.change_permission")
|
||||
def get_accessibility_data(request):
|
||||
"""
|
||||
Save accessibility filter method
|
||||
"""
|
||||
feature = request.GET["feature"]
|
||||
accessibility = DefaultAccessibility.objects.filter(feature=feature).first()
|
||||
if not accessibility:
|
||||
return JsonResponse("", safe=False)
|
||||
return JsonResponse(accessibility.filter)
|
||||
@@ -1,5 +1,4 @@
|
||||
import calendar
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
@@ -11,17 +10,17 @@ from django.conf import settings
|
||||
from django.contrib.staticfiles import finders
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import models
|
||||
from django.db.models import F, ForeignKey, ManyToManyField, OneToOneField, Q
|
||||
from django.db.models import ForeignKey, ManyToManyField, OneToOneField, Q
|
||||
from django.db.models.functions import Lower
|
||||
from django.forms.models import ModelChoiceField
|
||||
from django.http import HttpResponse
|
||||
from django.template.loader import get_template, render_to_string
|
||||
from django.template.loader import get_template
|
||||
from django.utils.translation import gettext as _
|
||||
from xhtml2pdf import pisa
|
||||
|
||||
from base.models import Company, CompanyLeaves, DynamicPagination, Holidays
|
||||
from employee.models import Employee, EmployeeWorkInformation
|
||||
from horilla.decorators import login_required
|
||||
from horilla.horilla_middlewares import _thread_locals
|
||||
from horilla.horilla_settings import HORILLA_DATE_FORMATS, HORILLA_TIME_FORMATS
|
||||
|
||||
|
||||
|
||||
0
employee/accessibility.py
Normal file
0
employee/accessibility.py
Normal file
@@ -11,13 +11,10 @@ import uuid
|
||||
import django
|
||||
import django_filters
|
||||
from django import forms
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.utils.translation import gettext as _
|
||||
from django_filters import CharFilter, DateFilter
|
||||
from django_filters import CharFilter
|
||||
|
||||
# from attendance.models import Attendance
|
||||
from base.methods import reload_queryset
|
||||
from base.models import WorkType
|
||||
from employee.models import DisciplinaryAction, Employee, Policy
|
||||
from horilla.filters import FilterSet, filter_by_name
|
||||
from horilla_documents.models import Document
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
employee/methods.py
|
||||
"""
|
||||
|
||||
import re
|
||||
from itertools import groupby
|
||||
|
||||
from django.db import models
|
||||
|
||||
@@ -7,6 +7,7 @@ To set Horilla sidebar for employee
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as trans
|
||||
|
||||
from accessibility.methods import check_is_accessibile
|
||||
from base.templatetags.basefilters import is_reportingmanager
|
||||
|
||||
MENU = trans("Employee")
|
||||
@@ -21,6 +22,7 @@ SUBMENUS = [
|
||||
{
|
||||
"menu": trans("Employees"),
|
||||
"redirect": reverse("employee-view"),
|
||||
"accessibility": "employee.sidebar.employee_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": trans("Document Requests"),
|
||||
@@ -86,3 +88,16 @@ def rotating_work_type_accessibility(request, submenu, user_perms, *args, **kwar
|
||||
return request.user.has_perm(
|
||||
"base.view_rotatingworktypeassign"
|
||||
) or is_reportingmanager(request.user)
|
||||
|
||||
|
||||
def employee_accessibility(request, submenu, user_perms, *args, **kwargs):
|
||||
"""
|
||||
Employee accessibility method
|
||||
"""
|
||||
cache_key = request.session.session_key + "accessibility_filter"
|
||||
employee = getattr(request.user, "employee_get")
|
||||
return (
|
||||
is_reportingmanager(request.user)
|
||||
or request.user.has_perm("employee.view_employee")
|
||||
or check_is_accessibile("employee_view", cache_key, employee)
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ from django.utils.translation import gettext as __
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from accessibility.decorators import enter_if_accessible
|
||||
from base.forms import ModelForm
|
||||
from base.methods import (
|
||||
choosesubordinates,
|
||||
@@ -155,6 +156,11 @@ filter_mapping = {
|
||||
}
|
||||
|
||||
|
||||
def _check_reporting_manager(request):
|
||||
employee = request.user.employee_get
|
||||
return employee.reporting_manager.exists()
|
||||
|
||||
|
||||
# Create your views here.
|
||||
@login_required
|
||||
def get_language_code(request):
|
||||
@@ -233,6 +239,11 @@ def self_info_update(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@enter_if_accessible(
|
||||
feature="employee_detailed_view",
|
||||
perm="employee.view_employee",
|
||||
method=_check_reporting_manager,
|
||||
)
|
||||
def employee_view_individual(request, obj_id, **kwargs):
|
||||
"""
|
||||
This method is used to view profile of an employee.
|
||||
@@ -894,6 +905,11 @@ def paginator_qry(qryset, page_number):
|
||||
|
||||
|
||||
@login_required
|
||||
@enter_if_accessible(
|
||||
feature="employee_view",
|
||||
perm="employee.view_employee",
|
||||
method=_check_reporting_manager,
|
||||
)
|
||||
def employee_view(request):
|
||||
"""
|
||||
This method is used to render template for view all employee
|
||||
@@ -1591,6 +1607,11 @@ def employee_update_bank_details(request, obj_id=None):
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
@enter_if_accessible(
|
||||
feature="employee_view",
|
||||
perm="employee.view_employee",
|
||||
method=_check_reporting_manager,
|
||||
)
|
||||
def employee_filter_view(request):
|
||||
"""
|
||||
This method is used to filter employee.
|
||||
@@ -2046,7 +2067,11 @@ def get_manager_in(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@manager_can_enter("employee.view_employee")
|
||||
@enter_if_accessible(
|
||||
feature="employee_view",
|
||||
perm="employee.view_employee",
|
||||
method=_check_reporting_manager,
|
||||
)
|
||||
def employee_search(request):
|
||||
"""
|
||||
This method is used to search employee
|
||||
|
||||
@@ -106,8 +106,13 @@ class HorillaFilterSet(FilterSet):
|
||||
HorillaFilterSet
|
||||
"""
|
||||
|
||||
verbose_name: dict = {}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
for key, value in self.verbose_name.items():
|
||||
self.form.fields[key].label = value
|
||||
|
||||
request = getattr(_thread_locals, "request", None)
|
||||
if request:
|
||||
setattr(request, "is_filtering", True)
|
||||
|
||||
@@ -7,6 +7,7 @@ This module is used to register horilla addons
|
||||
from horilla import settings
|
||||
from horilla.settings import INSTALLED_APPS
|
||||
|
||||
INSTALLED_APPS.append("accessibility")
|
||||
INSTALLED_APPS.append("horilla_audit")
|
||||
INSTALLED_APPS.append("horilla_widgets")
|
||||
INSTALLED_APPS.append("horilla_crumbs")
|
||||
|
||||
@@ -14,6 +14,7 @@ from horilla.settings import MIDDLEWARE
|
||||
MIDDLEWARE.append("base.middleware.CompanyMiddleware")
|
||||
MIDDLEWARE.append("horilla.horilla_middlewares.MethodNotAllowedMiddleware")
|
||||
MIDDLEWARE.append("horilla.horilla_middlewares.ThreadLocalMiddleware")
|
||||
MIDDLEWARE.append("accessibility.middlewares.AccessibilityMiddleware")
|
||||
_thread_locals = threading.local()
|
||||
|
||||
|
||||
|
||||
@@ -70,6 +70,16 @@
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
{% if perms.auth.view_permission %}
|
||||
<a
|
||||
id="defaultAccessibility"
|
||||
href="{% url 'user-accessibility' %}"
|
||||
class="oh-inner-sidebar__link oh-dropdown__link"
|
||||
>{% trans "Accessibility Restriction" %}</a
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
{% if perms.auth.view_group %}
|
||||
<a
|
||||
@@ -110,6 +120,16 @@
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
{% if perms.base.view_dynamicemailconfiguration %}
|
||||
<a
|
||||
id="date"
|
||||
{% comment %} href="{% url 'gdrive' %}" {% endcomment %}
|
||||
class="oh-inner-sidebar__link oh-dropdown__link"
|
||||
>{% trans "Gdrive Backup" %}</a
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user