[IMP] HORILLA: Restructure settings configuration for Horilla

This commit is contained in:
Horilla
2025-11-11 12:59:16 +05:30
parent 4768153be6
commit ac00e81bae
13 changed files with 512 additions and 634 deletions

View File

@@ -1,11 +1,3 @@
"""
init.py
"""
from horilla import (
horilla_apps,
horilla_context_processors,
horilla_middlewares,
horilla_settings,
rest_conf,
)

View File

@@ -11,13 +11,11 @@ from django.apps import apps
from django.conf import settings
from django.contrib.auth.context_processors import PermWrapper
from horilla.horilla_apps import SIDEBARS
logger = logging.getLogger(__name__)
def get_apps_in_base_dir():
return SIDEBARS
return settings.SIDEBARS
def import_method(accessibility):
@@ -89,3 +87,32 @@ def get_MENUS(request):
ALL_MENUS[request.session.session_key] = []
sidebar(request)
return {"sidebar": ALL_MENUS.get(request.session.session_key)}
def load_ldap_settings():
"""
Fetch LDAP settings dynamically from the database after Django is ready.
"""
try:
from django.db import connection
from horilla_ldap.models import LDAPSettings
# Ensure DB is ready before querying
if not connection.introspection.table_names():
print("⚠️ Database is empty. Using default LDAP settings.")
return settings.DEFAULT_LDAP_CONFIG
ldap_config = LDAPSettings.objects.first()
if ldap_config:
return {
"LDAP_SERVER": ldap_config.ldap_server,
"BIND_DN": ldap_config.bind_dn,
"BIND_PASSWORD": ldap_config.bind_password,
"BASE_DN": ldap_config.base_dn,
}
except Exception as e:
print(f"⚠️ Warning: Could not load LDAP settings ({e})")
return settings.DEFAULT_LDAP_CONFIG # Return default on error
return settings.DEFAULT_LDAP_CONFIG # Fallback in case of an issue

View File

@@ -1,71 +0,0 @@
"""
horilla_apps
This module is used to register horilla addons
"""
import os
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")
INSTALLED_APPS.append("horilla_documents")
INSTALLED_APPS.append("horilla_views")
INSTALLED_APPS.append("horilla_automations")
INSTALLED_APPS.append("auditlog")
INSTALLED_APPS.append("biometric")
INSTALLED_APPS.append("helpdesk")
INSTALLED_APPS.append("offboarding")
INSTALLED_APPS.append("horilla_backup")
INSTALLED_APPS.append("project")
INSTALLED_APPS.append("horilla_meet")
INSTALLED_APPS.append("report")
INSTALLED_APPS.append("whatsapp")
if settings.env("AWS_ACCESS_KEY_ID", default=None) and "storages" not in INSTALLED_APPS:
INSTALLED_APPS.append("storages")
AUDITLOG_INCLUDE_ALL_MODELS = True
AUDITLOG_EXCLUDE_TRACKING_MODELS = (
# "<app_name>",
# "<app_name>.<model>"
)
setattr(settings, "AUDITLOG_INCLUDE_ALL_MODELS", AUDITLOG_INCLUDE_ALL_MODELS)
setattr(settings, "AUDITLOG_EXCLUDE_TRACKING_MODELS", AUDITLOG_EXCLUDE_TRACKING_MODELS)
settings.MIDDLEWARE.append(
"auditlog.middleware.AuditlogMiddleware",
)
SETTINGS_EMAIL_BACKEND = getattr(settings, "EMAIL_BACKEND", False)
setattr(settings, "EMAIL_BACKEND", "base.backends.ConfiguredEmailBackend")
if SETTINGS_EMAIL_BACKEND:
setattr(settings, "EMAIL_BACKEND", SETTINGS_EMAIL_BACKEND)
# os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
SIDEBARS = [
"recruitment",
"onboarding",
"employee",
"attendance",
"leave",
"payroll",
"pms",
"offboarding",
"asset",
"helpdesk",
"project",
"report",
]
WHITE_LABELLING = False
NESTED_SUBORDINATE_VISIBILITY = False
TWO_FACTORS_AUTHENTICATION = False

View File

@@ -1,45 +0,0 @@
"""
horilla_context_process.py
This module is used to register context processors without effecting the horilla/settings.py module
"""
from horilla.settings import TEMPLATES
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"horilla.config.get_MENUS",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.get_companies",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.white_labelling_company",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.resignation_request_enabled",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.timerunner_enabled",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.intial_notice_period",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.check_candidate_self_tracking",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.check_candidate_self_tracking_rating",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.get_initial_prefix",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.biometric_app_exists",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.enable_late_come_early_out_tracking",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.enable_profile_edit",
)

View File

@@ -9,16 +9,6 @@ import threading
from django.http import HttpResponseNotAllowed
from django.shortcuts import render
from horilla.settings import MIDDLEWARE
MIDDLEWARE.append("base.middleware.CompanyMiddleware")
MIDDLEWARE.append("horilla.horilla_middlewares.MethodNotAllowedMiddleware")
MIDDLEWARE.append("horilla.horilla_middlewares.ThreadLocalMiddleware")
MIDDLEWARE.append("horilla.horilla_middlewares.SVGSecurityMiddleware")
MIDDLEWARE.append("accessibility.middlewares.AccessibilityMiddleware")
MIDDLEWARE.append("accessibility.middlewares.AccessibilityMiddleware")
MIDDLEWARE.append("base.middleware.ForcePasswordChangeMiddleware")
MIDDLEWARE.append("base.middleware.TwoFactorAuthMiddleware")
_thread_locals = threading.local()

View File

@@ -1,168 +0,0 @@
from django.core.files.storage import FileSystemStorage
from horilla import settings
from horilla.horilla_apps import INSTALLED_APPS
"""
DB_INIT_PASSWORD: str
The password used for database setup and initialization. This password is a
48-character alphanumeric string generated using a UUID to ensure high entropy and security.
"""
DB_INIT_PASSWORD = settings.env(
"DB_INIT_PASSWORD", default="d3f6a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d"
)
HORILLA_DATE_FORMATS = {
"DD/MM/YY": "%d/%m/%y",
"DD-MM-YYYY": "%d-%m-%Y",
"DD.MM.YYYY": "%d.%m.%Y",
"DD/MM/YYYY": "%d/%m/%Y",
"MM/DD/YYYY": "%m/%d/%Y",
"YYYY-MM-DD": "%Y-%m-%d",
"YYYY/MM/DD": "%Y/%m/%d",
"MMMM D, YYYY": "%B %d, %Y",
"DD MMMM, YYYY": "%d %B, %Y",
"MMM. D, YYYY": "%b. %d, %Y",
"D MMM. YYYY": "%d %b. %Y",
"dddd, MMMM D, YYYY": "%A, %B %d, %Y",
}
HORILLA_TIME_FORMATS = {
"hh:mm A": "%I:%M %p", # 12-hour format
"HH:mm": "%H:%M", # 24-hour format
"HH:mm:ss.SSSSSS": "%H:%M:%S.%f", # 24-hour format with seconds and microseconds
}
BIO_DEVICE_THREADS = {}
DYNAMIC_URL_PATTERNS = []
FILE_STORAGE = FileSystemStorage(location="csv_tmp/")
APP_URLS = [
"base.urls",
"employee.urls",
]
APPS = [
"base",
"employee",
"horilla_documents",
"horilla_automations",
]
NO_PERMISSION_MODALS = [
"historicalbonuspoint",
"assetreport",
"assetdocuments",
"returnimages",
"holiday",
"companyleave",
"historicalavailableleave",
"historicalleaverequest",
"historicalleaveallocationrequest",
"leaverequestconditionapproval",
"historicalcompensatoryleaverequest",
"employeepastleaverestrict",
"overrideleaverequests",
"historicalrotatingworktypeassign",
"employeeshiftday",
"historicalrotatingshiftassign",
"historicalworktyperequest",
"historicalshiftrequest",
"multipleapprovalmanagers",
"attachment",
"announcementview",
"emaillog",
"driverviewed",
"dashboardemployeecharts",
"attendanceallowedip",
"tracklatecomeearlyout",
"historicalcontract",
"overrideattendance",
"overrideleaverequest",
"overrideworkinfo",
"multiplecondition",
"historicalpayslip",
"reimbursementmultipleattachment",
"historicalcontract",
"overrideattendance",
"overrideleaverequest",
"workrecord",
"historicalticket",
"skill",
"historicalcandidate",
"rejectreason",
"historicalrejectedcandidate",
"rejectedcandidate",
"stagefiles",
"stagenote",
"questionordering",
"recruitmentsurveyordering",
"recruitmentsurveyanswer",
"recruitmentgeneralsetting",
"resume",
"recruitmentmailtemplate",
"profileeditfeature",
]
if settings.env("AWS_ACCESS_KEY_ID", default=None):
AWS_ACCESS_KEY_ID = settings.env("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = settings.env("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = settings.env("AWS_STORAGE_BUCKET_NAME")
AWS_S3_REGION_NAME = settings.env("AWS_S3_REGION_NAME")
DEFAULT_FILE_STORAGE = settings.env("DEFAULT_FILE_STORAGE")
AWS_S3_ADDRESSING_STYLE = settings.env("AWS_S3_ADDRESSING_STYLE")
settings.AWS_ACCESS_KEY_ID = AWS_ACCESS_KEY_ID
settings.AWS_SECRET_ACCESS_KEY = AWS_SECRET_ACCESS_KEY
settings.AWS_STORAGE_BUCKET_NAME = AWS_STORAGE_BUCKET_NAME
settings.AWS_S3_REGION_NAME = AWS_S3_REGION_NAME
settings.DEFAULT_FILE_STORAGE = DEFAULT_FILE_STORAGE
settings.AWS_S3_ADDRESSING_STYLE = AWS_S3_ADDRESSING_STYLE
if settings.env("AWS_ACCESS_KEY_ID", default=None) and "storages" in INSTALLED_APPS:
settings.MEDIA_URL = f"{settings.env('MEDIA_URL')}/{settings.env('NAMESPACE')}/"
settings.MEDIA_ROOT = f"{settings.env('MEDIA_ROOT')}/{settings.env('NAMESPACE')}/"
# Default LDAP settings
DEFAULT_LDAP_CONFIG = {
"LDAP_SERVER": settings.env("LDAP_SERVER", default="ldap://127.0.0.1:389"),
"BIND_DN": settings.env("BIND_DN", default="cn=admin,dc=horilla,dc=com"),
"BIND_PASSWORD": settings.env("BIND_PASSWORD", default="horilla"),
"BASE_DN": settings.env("BASE_DN", default="ou=users,dc=horilla,dc=com"),
}
def load_ldap_settings():
"""
Fetch LDAP settings dynamically from the database after Django is ready.
"""
try:
from django.db import connection
from horilla_ldap.models import LDAPSettings
# Ensure DB is ready before querying
if not connection.introspection.table_names():
print("⚠️ Database is empty. Using default LDAP settings.")
return DEFAULT_LDAP_CONFIG
ldap_config = LDAPSettings.objects.first()
if ldap_config:
return {
"LDAP_SERVER": ldap_config.ldap_server,
"BIND_DN": ldap_config.bind_dn,
"BIND_PASSWORD": ldap_config.bind_password,
"BASE_DN": ldap_config.base_dn,
}
except Exception as e:
print(f"⚠️ Warning: Could not load LDAP settings ({e})")
return DEFAULT_LDAP_CONFIG # Return default on error
return DEFAULT_LDAP_CONFIG # Fallback in case of an issue

View File

@@ -1,10 +1,10 @@
import contextlib
import importlib
from django.contrib.auth.models import User
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from horilla.horilla_settings import APP_URLS, DYNAMIC_URL_PATTERNS
from horilla_auth.models import HorillaUser
def get_horilla_model_class(app_label, model):
@@ -63,12 +63,12 @@ def horilla_users_with_perms(permissions):
permissions = [permissions]
# Start with a queryset that includes all superusers
users_with_permissions = User.objects.filter(is_superuser=True)
users_with_permissions = HorillaUser.objects.filter(is_superuser=True)
# Filter users based on the permissions list
for perm in permissions:
app_label, codename = perm.split(".")
users_with_permissions |= User.objects.filter(
users_with_permissions |= HorillaUser.objects.filter(
user_permissions__codename=codename,
user_permissions__content_type__app_label=app_label,
)
@@ -87,7 +87,7 @@ def remove_dynamic_url(path_info):
"""Function to remove a dynamically added URL from any app's urlpatterns."""
# Iterate over all app URL patterns
for app_urls in APP_URLS:
for app_urls in settings.APP_URLS:
try:
# Dynamically import the app's urls.py module
urls_module = importlib.import_module(app_urls)
@@ -105,5 +105,5 @@ def remove_dynamic_url(path_info):
print(f"Module {app_urls} not found. Skipping...")
# Also remove it from the tracked dynamic paths
if path_info in DYNAMIC_URL_PATTERNS:
DYNAMIC_URL_PATTERNS.remove(path_info)
if path_info in settings.DYNAMIC_URL_PATTERNS:
settings.DYNAMIC_URL_PATTERNS.remove(path_info)

View File

@@ -13,7 +13,6 @@ from uuid import uuid4
from auditlog.models import AuditlogHistoryField
from auditlog.registry import auditlog
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.fields.files import FieldFile
@@ -22,6 +21,7 @@ from django.utils.text import slugify
from django.utils.translation import gettext as _
from horilla.horilla_middlewares import _thread_locals
from horilla_auth.models import HorillaUser
@property
@@ -96,7 +96,7 @@ class HorillaModel(models.Model):
verbose_name=_("Created At"),
)
created_by = models.ForeignKey(
User,
HorillaUser,
on_delete=models.SET_NULL,
null=True,
blank=True,
@@ -105,7 +105,7 @@ class HorillaModel(models.Model):
)
modified_by = models.ForeignKey(
User,
HorillaUser,
on_delete=models.SET_NULL,
null=True,
blank=True,
@@ -146,7 +146,7 @@ class HorillaModel(models.Model):
if (
hasattr(self, "created_by")
and hasattr(self._meta.get_field("created_by"), "related_model")
and self._meta.get_field("created_by").related_model == User
and self._meta.get_field("created_by").related_model == HorillaUser
):
if request and not self.pk:
if user.is_authenticated:

View File

@@ -1,46 +0,0 @@
"""
rest_conf.py
"""
from datetime import timedelta
from horilla import settings
from horilla.settings import INSTALLED_APPS
# Injecting installed apps to settings
REST_APPS = ["rest_framework", "rest_framework_simplejwt", "drf_yasg", "horilla_api"]
INSTALLED_APPS.extend(REST_APPS)
REST_FRAMEWORK_SETTINGS = {
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"PAGE_SIZE": 20,
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=30),
}
SWAGGER_SETTINGS = {
"SECURITY_DEFINITIONS": {
"Bearer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"description": "Enter your Bearer token here",
},
"Basic": {
"type": "basic",
"description": "Basic authentication. Enter your username and password.",
},
},
"SECURITY": [{"Bearer": []}, {"Basic": []}],
}
# Inject the REST framework settings into the Django project settings
setattr(settings, "REST_FRAMEWORK", REST_FRAMEWORK_SETTINGS)
setattr(settings, "SIMPLE_JWT", SIMPLE_JWT)
setattr(settings, "SWAGGER_SETTINGS", SWAGGER_SETTINGS)

View File

@@ -1,272 +0,0 @@
"""
Django settings for horilla project.
Generated by 'django-admin startproject' using Django 4.1.4.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""
import os
from os.path import join
from pathlib import Path
import environ
from django.contrib.messages import constants as messages
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
env = environ.Env(
DEBUG=(bool, True),
SECRET_KEY=(
str,
"django-insecure-j8op9)1q8$1&0^s&p*_0%d#pr@w9qj@1o=3#@d=a(^@9@zd@%j",
),
ALLOWED_HOSTS=(list, ["*"]),
CSRF_TRUSTED_ORIGINS=(list, ["http://localhost:8000"]),
)
env.read_env(os.path.join(BASE_DIR, ".env"), overwrite=True)
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env("DEBUG")
ALLOWED_HOSTS = env("ALLOWED_HOSTS")
# Application definition
THEME_APP = "horilla_theme"
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"notifications",
"mathfilters",
"corsheaders",
"simple_history",
"django_filters",
THEME_APP,
"base",
"employee",
"recruitment",
"leave",
"pms",
"onboarding",
"asset",
"attendance",
"payroll",
"widget_tweaks",
"django_apscheduler",
]
APSCHEDULER_DATETIME_FORMAT = "N j, Y, f:s a"
APSCHEDULER_RUN_NOW_TIMEOUT = 25 # Seconds
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"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",
]
ROOT_URLCONF = "horilla.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
BASE_DIR / "templates",
],
"APP_DIRS": False,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
"loaders": [
(
"django.template.loaders.filesystem.Loader",
[BASE_DIR / THEME_APP / "templates"],
),
"django.template.loaders.app_directories.Loader",
("django.template.loaders.filesystem.Loader", [BASE_DIR / "templates"]),
],
},
},
]
WSGI_APPLICATION = "horilla.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
if env("DATABASE_URL", default=None):
DATABASES = {
"default": env.db(),
}
else:
DATABASES = {
"default": {
"ENGINE": env("DB_ENGINE", default="django.db.backends.sqlite3"),
"NAME": env(
"DB_NAME",
default=os.path.join(
BASE_DIR,
"TestDB.sqlite3",
),
),
"USER": env("DB_USER", default=""),
"PASSWORD": env("DB_PASSWORD", default=""),
"HOST": env("DB_HOST", default=""),
"PORT": env("DB_PORT", default=""),
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_DIRS = [
BASE_DIR / "static",
]
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
MESSAGE_TAGS = {
messages.DEBUG: "oh-alert--warning",
messages.INFO: "oh-alert--info",
messages.SUCCESS: "oh-alert--success",
messages.WARNING: "oh-alert--warning",
messages.ERROR: "oh-alert--danger",
}
CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS")
LOGIN_URL = "/login"
SIMPLE_HISTORY_REVERT_DISABLED = True
DJANGO_NOTIFICATIONS_CONFIG = {
"USE_JSONFIELD": True,
"SOFT_DELETE": True,
"USE_WATCHED": True,
"NOTIFICATIONS_STORAGE": "notifications.storage.DatabaseStorage",
"TEMPLATE": "notifications.html", # Add this line
}
X_FRAME_OPTIONS = "SAMEORIGIN"
LANGUAGES = (
("en", "English (US)"),
("de", "Deutsche"),
("es", "Español"),
("fr", "Français"),
("ar", "عربى"),
("pt-br", "Português (Brasil)"),
("zh-hans", "Simplified Chinese"),
("zh-hant", "Traditional Chinese"),
("it", "Italian"),
)
LOCALE_PATHS = [
join(BASE_DIR, "horilla", "locale"),
]
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = env("TIME_ZONE", default="Asia/Kolkata")
USE_I18N = True
USE_L10N = True
USE_TZ = True
# LDAP Configuration
# import ldap
# from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
AUTH_LDAP_SERVER_URI = "ldap://127.0.0.1:389" # Replace with your LDAP server address
# Bind credentials, if required
AUTH_LDAP_BIND_DN = "cn=admin,dc=horilla,dc=com" # Replace with your bind DN
AUTH_LDAP_BIND_PASSWORD = "your_password" # Replace with your LDAP bind password
# Define the search base and user lookup
# AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=users,dc=horilla,dc=com", ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
# Map LDAP fields to Django user fields
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
"last_name": "sn",
"email": "mail",
}
AUTHENTICATION_BACKENDS = [
# "django_auth_ldap.backend.LDAPBackend",
"django.contrib.auth.backends.ModelBackend",
]
AUTH_LDAP_ALWAYS_UPDATE_USER = True

View File

@@ -0,0 +1,13 @@
"""
horilla/settings/__init__.py
Combines official base settings + client overrides.
"""
from .base import *
# Import client overrides (if file exists)
try:
from .local_settings import *
from .addons import *
except ImportError:
pass

View File

@@ -0,0 +1,16 @@
from .local_settings import *
if env("AWS_ACCESS_KEY_ID", default=None):
AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME")
AWS_S3_REGION_NAME = env("AWS_S3_REGION_NAME")
DEFAULT_FILE_STORAGE = env("DEFAULT_FILE_STORAGE")
AWS_S3_ADDRESSING_STYLE = env("AWS_S3_ADDRESSING_STYLE")
if env("AWS_ACCESS_KEY_ID", default=None) and "storages" not in INSTALLED_APPS:
INSTALLED_APPS.append("storages")
if env("AWS_ACCESS_KEY_ID", default=None) and "storages" in INSTALLED_APPS:
MEDIA_URL = f"{env('MEDIA_URL')}/{env('NAMESPACE')}/"
MEDIA_ROOT = f"{env('MEDIA_ROOT')}/{env('NAMESPACE')}/"

442
horilla/settings/base.py Normal file
View File

@@ -0,0 +1,442 @@
"""
base.py — Main Django settings for Horilla
"""
import os
from os.path import join
from pathlib import Path
from datetime import timedelta
import environ
from django.contrib.messages import constants as messages
from django.core.files.storage import FileSystemStorage
# ========================================
# BASE PATH & ENVIRONMENT CONFIGURATION
# ========================================
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env = environ.Env(
DEBUG=(bool, True),
SECRET_KEY=(str, "django-insecure-default-key"),
ALLOWED_HOSTS=(list, ["*"]),
CSRF_TRUSTED_ORIGINS=(list, ["http://localhost:8000"]),
)
env.read_env(os.path.join(BASE_DIR, ".env"), overwrite=True)
# ========================================
# CORE DJANGO SETTINGS
# ========================================
SECRET_KEY = env("SECRET_KEY")
DEBUG = env("DEBUG")
ALLOWED_HOSTS = env("ALLOWED_HOSTS")
CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS")
THEME_APP = "horilla_theme"
INSTALLED_APPS = [
# Default Django apps
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Third-party apps
"notifications",
"mathfilters",
"corsheaders",
"simple_history",
"django_filters",
"widget_tweaks",
"auditlog",
"django_apscheduler",
"rest_framework",
"rest_framework_simplejwt",
"drf_yasg",
# Core Horilla apps
"horilla_auth",
THEME_APP,
"base",
"employee",
"recruitment",
"leave",
"pms",
"onboarding",
"asset",
"attendance",
"payroll",
"accessibility",
"horilla_audit",
"horilla_widgets",
"horilla_crumbs",
"horilla_documents",
"horilla_views",
"horilla_automations",
"horilla_api",
"biometric",
"helpdesk",
"offboarding",
"horilla_backup",
"project",
"horilla_meet",
"report",
"whatsapp",
]
# ========================================
# REST FRAMEWORK CONFIGURATION
# ========================================
REST_FRAMEWORK = {
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"PAGE_SIZE": 20,
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=30),
}
SWAGGER_SETTINGS = {
"SECURITY_DEFINITIONS": {
"Bearer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"description": "Enter your Bearer token here",
},
"Basic": {"type": "basic", "description": "Basic authentication."},
},
"SECURITY": [{"Bearer": []}, {"Basic": []}],
}
APSCHEDULER_DATETIME_FORMAT = "N j, Y, f:s a"
APSCHEDULER_RUN_NOW_TIMEOUT = 25 # Seconds
# ========================================
# MIDDLEWARE
# ========================================
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"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",
# Horilla-specific middlewares
"base.middleware.CompanyMiddleware",
"base.middleware.ForcePasswordChangeMiddleware",
"base.middleware.TwoFactorAuthMiddleware",
"accessibility.middlewares.AccessibilityMiddleware",
"horilla.horilla_middlewares.MethodNotAllowedMiddleware",
"horilla.horilla_middlewares.ThreadLocalMiddleware",
"horilla.horilla_middlewares.SVGSecurityMiddleware",
"auditlog.middleware.AuditlogMiddleware",
]
ROOT_URLCONF = "horilla.urls"
# ========================================
# DATABASE CONFIGURATION
# ========================================
if env("DATABASE_URL", default=None):
DATABASES = {"default": env.db()}
else:
DATABASES = {
"default": {
"ENGINE": env("DB_ENGINE", default="django.db.backends.sqlite3"),
"NAME": env("DB_NAME", default=os.path.join(BASE_DIR, "db.sqlite3")),
"USER": env("DB_USER", default=""),
"PASSWORD": env("DB_PASSWORD", default=""),
"HOST": env("DB_HOST", default=""),
"PORT": env("DB_PORT", default=""),
}
}
# ========================================
# STATIC & MEDIA FILES
# ========================================
STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_DIRS = [BASE_DIR / "static"]
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
# ========================================
# AUTHENTICATION & SECURITY
# ========================================
AUTH_PASSWORD_VALIDATORS = [
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
]
AUTH_USER_MODEL = 'horilla_auth.HorillaUser'
X_FRAME_OPTIONS = "SAMEORIGIN"
# ========================================
# TEMPLATES
# ========================================
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": False,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
# Horilla dynamic context processors
"horilla.config.get_MENUS",
"base.context_processors.get_companies",
"base.context_processors.white_labelling_company",
"base.context_processors.resignation_request_enabled",
"base.context_processors.timerunner_enabled",
"base.context_processors.intial_notice_period",
"base.context_processors.check_candidate_self_tracking",
"base.context_processors.check_candidate_self_tracking_rating",
"base.context_processors.get_initial_prefix",
"base.context_processors.biometric_app_exists",
"base.context_processors.enable_late_come_early_out_tracking",
"base.context_processors.enable_profile_edit",
],
"loaders": [
(
"django.template.loaders.filesystem.Loader",
[BASE_DIR / THEME_APP / "templates"]
),
"django.template.loaders.app_directories.Loader",
(
"django.template.loaders.filesystem.Loader",
[BASE_DIR / "templates"]
),
],
},
},
]
WSGI_APPLICATION = "horilla.wsgi.application"
# ========================================
# INTERNATIONALIZATION
# ========================================
LANGUAGE_CODE = "en-us"
TIME_ZONE = env("TIME_ZONE", default="Asia/Kolkata")
USE_I18N = True
USE_TZ = True
LANGUAGES = (
("en", "English (US)"),
("de", "Deutsche"),
("es", "Español"),
("fr", "Français"),
("ar", "عربى"),
("pt-br", "Português (Brasil)"),
("zh-hans", "Simplified Chinese"),
("zh-hant", "Traditional Chinese"),
("it", "Italian"),
)
LOCALE_PATHS = [join(BASE_DIR, "horilla", "locale")]
# ========================================
# LOGGING, MESSAGES, OTHER GLOBALS
# ========================================
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
MESSAGE_TAGS = {
messages.DEBUG: "oh-alert--warning",
messages.INFO: "oh-alert--info",
messages.SUCCESS: "oh-alert--success",
messages.WARNING: "oh-alert--warning",
messages.ERROR: "oh-alert--danger",
}
LOGIN_URL = "/login"
SIMPLE_HISTORY_REVERT_DISABLED = True
DJANGO_NOTIFICATIONS_CONFIG = {
"USE_JSONFIELD": True,
"SOFT_DELETE": True,
"USE_WATCHED": True,
"NOTIFICATIONS_STORAGE": "notifications.storage.DatabaseStorage",
"TEMPLATE": "notifications.html",
}
# ========================================
# HORILLA-SPECIFIC SETTINGS
# ========================================
WHITE_LABELLING = False
NESTED_SUBORDINATE_VISIBILITY = False
TWO_FACTORS_AUTHENTICATION = False
SIDEBARS = [
"recruitment",
"onboarding",
"employee",
"attendance",
"leave",
"payroll",
"pms",
"offboarding",
"asset",
"helpdesk",
"project",
"report",
]
AUDITLOG_INCLUDE_ALL_MODELS = True
AUDITLOG_EXCLUDE_TRACKING_MODELS = (
# "<app_name>",
# "<app_name>.<model>"
)
EMAIL_BACKEND = "base.backends.ConfiguredEmailBackend"
"""
DB_INIT_PASSWORD: str
The password used for database setup and initialization. This password is a
48-character alphanumeric string generated using a UUID to ensure high entropy and security.
"""
DB_INIT_PASSWORD = env(
"DB_INIT_PASSWORD", default="d3f6a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d"
)
# ========================================
# PERMISSIONS / CUSTOM LOGIC
# ========================================
NO_PERMISSION_MODALS = [
"historicalbonuspoint",
"assetreport",
"assetdocuments",
"returnimages",
"holiday",
"companyleave",
"historicalavailableleave",
"historicalleaverequest",
"historicalleaveallocationrequest",
"leaverequestconditionapproval",
"historicalcompensatoryleaverequest",
"employeepastleaverestrict",
"overrideleaverequests",
"historicalrotatingworktypeassign",
"employeeshiftday",
"historicalrotatingshiftassign",
"historicalworktyperequest",
"historicalshiftrequest",
"multipleapprovalmanagers",
"attachment",
"announcementview",
"emaillog",
"driverviewed",
"dashboardemployeecharts",
"attendanceallowedip",
"tracklatecomeearlyout",
"historicalcontract",
"overrideattendance",
"overrideleaverequest",
"overrideworkinfo",
"multiplecondition",
"historicalpayslip",
"reimbursementmultipleattachment",
"workrecord",
"historicalticket",
"skill",
"historicalcandidate",
"rejectreason",
"historicalrejectedcandidate",
"rejectedcandidate",
"stagefiles",
"stagenote",
"questionordering",
"recruitmentsurveyordering",
"recruitmentsurveyanswer",
"recruitmentgeneralsetting",
"resume",
"recruitmentmailtemplate",
"profileeditfeature",
]
FILE_STORAGE = FileSystemStorage(location="csv_tmp/")
HORILLA_DATE_FORMATS = {
"DD/MM/YY": "%d/%m/%y",
"DD-MM-YYYY": "%d-%m-%Y",
"DD.MM.YYYY": "%d.%m.%Y",
"DD/MM/YYYY": "%d/%m/%Y",
"MM/DD/YYYY": "%m/%d/%Y",
"YYYY-MM-DD": "%Y-%m-%d",
"YYYY/MM/DD": "%Y/%m/%d",
"MMMM D, YYYY": "%B %d, %Y",
"DD MMMM, YYYY": "%d %B, %Y",
"MMM. D, YYYY": "%b. %d, %Y",
"D MMM. YYYY": "%d %b. %Y",
"dddd, MMMM D, YYYY": "%A, %B %d, %Y",
}
HORILLA_TIME_FORMATS = {
"hh:mm A": "%I:%M %p", # 12-hour format
"HH:mm": "%H:%M", # 24-hour format
"HH:mm:ss.SSSSSS": "%H:%M:%S.%f", # 24-hour format with seconds and microseconds
}
BIO_DEVICE_THREADS = {}
DYNAMIC_URL_PATTERNS = []
APP_URLS = [
"base.urls",
"employee.urls",
]
APPS = [
"base",
"employee",
"horilla_documents",
"horilla_automations",
]
# ========================================
# LDAP CONFIGURATION (Default)
# ========================================
AUTH_LDAP_SERVER_URI = "ldap://127.0.0.1:389"
AUTH_LDAP_BIND_DN = "cn=admin,dc=horilla,dc=com"
AUTH_LDAP_BIND_PASSWORD = "your_password"
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
"last_name": "sn",
"email": "mail",
}
# Default LDAP settings
DEFAULT_LDAP_CONFIG = {
"LDAP_SERVER": env("LDAP_SERVER", default="ldap://127.0.0.1:389"),
"BIND_DN": env("BIND_DN", default="cn=admin,dc=horilla,dc=com"),
"BIND_PASSWORD": env("BIND_PASSWORD", default="horilla"),
"BASE_DN": env("BASE_DN", default="ou=users,dc=horilla,dc=com"),
}
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
# "django_auth_ldap.backend.LDAPBackend",
]
AUTH_LDAP_ALWAYS_UPDATE_USER = True