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

API Updates #516

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion base/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.db.models import Q
from django.http import HttpResponse, HttpResponseNotAllowed
from django.shortcuts import render

from django.shortcuts import redirect
from asset.models import AssetAssignment, AssetRequest
from attendance.models import (
Attendance,
Expand Down Expand Up @@ -181,3 +181,22 @@ def __call__(self, request):

response = self.get_response(request)
return response


#MIDDLEWARE TO CHECK IF EMPLOYEE IS NEW USER OR NOT
class ForcePasswordChangeMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
# Exclude specific paths from redirection
excluded_paths = ['/change-password', '/login', '/logout']
if request.path.rstrip('/') in excluded_paths:
return self.get_response(request)

# Check if employee is a new employee
if hasattr(request, 'user') and request.user.is_authenticated:
if getattr(request.user, 'is_new_employee', True):
return redirect('change-password') # Adjust to match your URL name

return self.get_response(request)
4 changes: 4 additions & 0 deletions base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from datetime import date, datetime, timedelta
from typing import Iterable

from django.contrib.auth.models import AbstractUser
import django
from django.apps import apps
from django.contrib import messages
Expand Down Expand Up @@ -1794,3 +1795,6 @@ def create_deduction_cutleave_from_penalty(sender, instance, created, **kwargs):
)

available.save()


User.add_to_class('is_new_employee', models.BooleanField(default=False))
1 change: 1 addition & 0 deletions base/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
),
path("reset-send-success", views.reset_send_success, name="reset-send-success"),
path("change-password", views.change_password, name="change-password"),

path("logout", views.logout_user, name="logout"),
path("settings", views.common_settings, name="settings"),
path(
Expand Down
12 changes: 12 additions & 0 deletions base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,11 @@ def change_password(request):
if form.is_valid():
new_password = form.cleaned_data["new_password"]
user.set_password(new_password)

if user.is_new_employee: # Ensure this only affects new employees
user.is_new_employee = False
user.save()

user = authenticate(request, username=user.username, password=new_password)
login(request, user)
messages.success(request, _("Password changed successfully"))
Expand All @@ -748,6 +752,14 @@ def change_password(request):
return render(request, "base/auth/password_change.html", {"form": form})










def logout_user(request):
"""
This method used to logout the user
Expand Down
7 changes: 7 additions & 0 deletions employee/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,19 @@ def save(self, *args, **kwargs):
if employee.employee_user_id is None:
# Create user if no corresponding user exists
username = self.email

password = self.phone

is_new_employee_flag = not employee.employee_user_id.is_new_employee if employee.employee_user_id else True
user = User.objects.create_user(
username=username, email=username, password=password, is_new_employee=is_new_employee_flag
)
user = User.objects.filter(username=username).first()
if not user:
user = User.objects.create_user(
username=username, email=username, password=password
)

self.employee_user_id = user
# default permissions
change_ownprofile = Permission.objects.get(codename="change_ownprofile")
Expand Down
2 changes: 2 additions & 0 deletions horilla/horilla_middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
MIDDLEWARE.append("horilla.horilla_middlewares.MethodNotAllowedMiddleware")
MIDDLEWARE.append("horilla.horilla_middlewares.ThreadLocalMiddleware")
MIDDLEWARE.append("accessibility.middlewares.AccessibilityMiddleware")
MIDDLEWARE.append("accessibility.middlewares.AccessibilityMiddleware")
MIDDLEWARE.append("base.middleware.ForcePasswordChangeMiddleware")
_thread_locals = threading.local()


Expand Down
3 changes: 3 additions & 0 deletions horilla/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,15 @@
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"corsheaders.middleware.CorsMiddleware",


"simple_history.middleware.HistoryRequestMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"base.middleware.ForcePasswordChangeMiddleware",
]

ROOT_URLCONF = "horilla.urls"
Expand Down
58 changes: 30 additions & 28 deletions horilla_api/api_urls/asset/urls.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
from django.urls import path, re_path
from django.urls import path, include
from rest_framework.routers import DefaultRouter

from ...api_views.asset.views import *
from ...api_views.asset.views import (
AssetViewSet,
AssetCategoryViewSet,
AssetLotViewSet,
AssetAssignmentViewSet,
AssetRequestViewSet,
)


router = DefaultRouter()
router.register(r'assets', AssetViewSet, basename='api-asset')
router.register(r'asset-categories', AssetCategoryViewSet, basename='api-asset-category')
router.register(r'asset-lots', AssetLotViewSet, basename='api-asset-lot')
router.register(r'asset-allocations', AssetAssignmentViewSet, basename='api-asset-allocation')
router.register(r'asset-requests', AssetRequestViewSet, basename='api-asset-request')

urlpatterns = [
re_path(
r"^asset-categories/(?P<pk>\d+)?$",
AssetCategoryAPIView.as_view(),
name="api-asset-category-detail",
),
re_path(
r"^asset-lots/(?P<pk>\d+)?$",
AssetLotAPIView.as_view(),
name="api-asset-lot-detail",
),
re_path(r"^assets/(?P<pk>\d+)?$", AssetAPIView.as_view(), name="api-asset-detail"),
re_path(
r"^asset-allocations/(?P<pk>\d+)?$",
AssetAllocationAPIView.as_view(),
name="api-asset-allocation-detail",
),
re_path(
r"^asset-requests/(?P<pk>\d+)?$",
AssetRequestAPIView.as_view(),
name="api-asset-request-detail",
),

path('', include(router.urls)),


path(
"asset-return/<int:pk>", AssetReturnAPIView.as_view(), name="api-asset-return"
'asset-return/<int:pk>/',
AssetAssignmentViewSet.as_view({'put': 'return_asset'}),
name='api-asset-return'
),
path(
"asset-reject/<int:pk>", AssetRejectAPIView.as_view(), name="api-asset-reject"
'asset-reject/<int:pk>/',
AssetRequestViewSet.as_view({'put': 'reject'}),
name='api-asset-reject'
),
path(
"asset-approve/<int:pk>",
AssetApproveAPIView.as_view(),
name="api-asset-approve",
'asset-approve/<int:pk>/',
AssetRequestViewSet.as_view({'put': 'approve'}),
name='api-asset-approve'
),
]
100 changes: 75 additions & 25 deletions horilla_api/api_urls/payroll/urls.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,83 @@
from django.urls import path
from django.urls import path, include
from rest_framework.routers import DefaultRouter

from ...api_views.payroll.views import *
from ...api_views.payroll.views import (
PayslipViewSet,
ContractViewSet,
LoanAccountViewSet,
ReimbursementViewSet,
TaxBracketViewSet,
AllowanceViewSet,
DeductionViewSet,
)

# Create a router for ViewSet-based URLs
router = DefaultRouter()
router.register(r'api/contract', ContractViewSet, basename='contract')
router.register(r'api/payslip', PayslipViewSet, basename='payslip')
router.register(r'api/loan-account', LoanAccountViewSet, basename='loan-account')
router.register(r'api/reimbursement', ReimbursementViewSet, basename='reimbursement')
router.register(r'api/tax-bracket', TaxBracketViewSet, basename='tax-bracket')
router.register(r'api/allowance', AllowanceViewSet, basename='allowance')
router.register(r'api/deduction', DeductionViewSet, basename='deduction')

# Define URL patterns, maintaining backward compatibility
urlpatterns = [
# Include router-generated URLs
path('', include(router.urls)),

# Legacy URL patterns for backward compatibility
path(
"contract/",
ContractView.as_view(),
ContractViewSet.as_view({'get': 'list', 'post': 'create'}),
name="legacy-contract-list"
),
path(
"contract/<int:id>",
ContractView.as_view(),
),
path("payslip/", PayslipView.as_view(), name=""),
path("payslip/<int:id>", PayslipView.as_view(), name=""),
path("payslip-download/<int:id>", PayslipDownloadView.as_view(), name=""),
path("payslip-send-mail/", PayslipSendMailView.as_view(), name=""),
path("loan-account/", LoanAccountView.as_view(), name=""),
path("loan-account/<int:pk>", LoanAccountView.as_view(), name=""),
path("reimbusement/", ReimbursementView.as_view(), name=""),
path("reimbusement/<int:pk>", ReimbursementView.as_view(), name=""),
path(
"reimbusement-approve-reject/<int:pk>",
ReimbusementApproveRejectView.as_view(),
name="",
),
path("tax-bracket/<int:pk>", TaxBracketView.as_view(), name=""),
path("tax-bracket/", TaxBracketView.as_view(), name=""),
path("allowance", AllowanceView.as_view(), name=""),
path("allowance/<int:pk>", AllowanceView.as_view(), name=""),
path("deduction", DeductionView.as_view(), name=""),
path("deduction/<int:pk>", DeductionView.as_view(), name=""),
]
ContractViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}),
name="legacy-contract-detail"
),
path(
"payslip/",
PayslipViewSet.as_view({'get': 'list', 'post': 'create'}),
name="legacy-payslip-list"
),
path(
"payslip/<int:id>",
PayslipViewSet.as_view({'get': 'retrieve'}),
name="legacy-payslip-detail"
),
path(
"payslip-download/<int:id>",
PayslipViewSet.as_view({'get': 'download'}),
name="legacy-payslip-download"
),
path(
"payslip-send-mail/",
PayslipViewSet.as_view({'post': 'send_mail'}),
name="legacy-payslip-send-mail"
),
path(
"reimbursement/",
ReimbursementViewSet.as_view({'get': 'list', 'post': 'create'}),
name="legacy-reimbursement-list"
),
path(
"reimbursement/<int:pk>",
ReimbursementViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}),
name="legacy-reimbursement-detail"
),
path(
"reimbursement-approve-reject/<int:pk>",
ReimbursementViewSet.as_view({'post': 'process_request'}),
name="legacy-reimbursement-approve-reject"
),
]
Loading