You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
6.0 KiB
162 lines
6.0 KiB
import json
|
|
import random
|
|
from functools import lru_cache
|
|
|
|
from django import forms
|
|
from django.conf import settings
|
|
from django.contrib.humanize.templatetags.humanize import intcomma
|
|
from django.urls import reverse
|
|
from django.utils.safestring import mark_safe
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import RedirectView
|
|
|
|
# Unfold Imports
|
|
from unfold.sites import UnfoldAdminSite
|
|
|
|
# ---------------------------------------------------------
|
|
# 1. Helper Functions
|
|
# ---------------------------------------------------------
|
|
|
|
def admin_url_generator(request, url_name):
|
|
"""
|
|
Dynamically generates admin URLs based on the current active panel.
|
|
Usage in settings.py: lambda request: admin_url_generator(request, "app_model_changelist")
|
|
"""
|
|
# 1. Determine the current namespace based on the URL path
|
|
if request.path.startswith('/en/dovoodi/') or request.path.startswith('/dovoodi/'):
|
|
namespace = 'dovoodi_admin'
|
|
else:
|
|
# Default to the main admin
|
|
namespace = 'imam_javad_admin'
|
|
|
|
# 2. Construct the view name (e.g., "imam_javad_admin:account_user_changelist")
|
|
full_view_name = f"{namespace}:{url_name}"
|
|
|
|
# 3. Resolve the URL
|
|
try:
|
|
return reverse(full_view_name)
|
|
except Exception:
|
|
# If the model isn't registered in this specific admin, return a dead link
|
|
# to prevent the whole page from crashing.
|
|
return "#"
|
|
|
|
def dashboard_callback(request, context):
|
|
context.update(random_data())
|
|
return context
|
|
|
|
def variables(request):
|
|
return {"plausible_domain": getattr(settings, 'PLAUSIBLE_DOMAIN', '')}
|
|
|
|
# ---------------------------------------------------------
|
|
# 2. Custom Login Form
|
|
# ---------------------------------------------------------
|
|
|
|
class LoginForm:
|
|
"""Lazy login form to avoid circular imports during settings loading"""
|
|
|
|
@staticmethod
|
|
def get_form():
|
|
# Import AuthenticationForm only when needed
|
|
from django.contrib.auth.forms import AuthenticationForm
|
|
|
|
class CustomLoginForm(AuthenticationForm):
|
|
password = forms.CharField(widget=forms.PasswordInput(render_value=True))
|
|
|
|
def __init__(self, request=None, *args, **kwargs):
|
|
super().__init__(request, *args, **kwargs)
|
|
# Change the label of the username field to "Email"
|
|
self.fields["username"].label = "Email"
|
|
|
|
return CustomLoginForm
|
|
|
|
# ---------------------------------------------------------
|
|
# 3. Admin Site Definitions
|
|
# ---------------------------------------------------------
|
|
|
|
class FormulaAdminSite(UnfoldAdminSite):
|
|
"""Main Admin for Imam Javad"""
|
|
site_header = "Imam Javad Admin"
|
|
site_title = "Imam Javad"
|
|
index_title = "System Administration"
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
# Set login form after initialization to avoid circular import
|
|
self.login_form = LoginForm.get_form()
|
|
|
|
class DovoodiAdminSite(UnfoldAdminSite):
|
|
"""Secondary Admin for Dovoodi"""
|
|
site_header = "Dovoodi Admin"
|
|
site_title = "Dovoodi"
|
|
index_title = "System Administration"
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
# Set login form after initialization to avoid circular import
|
|
self.login_form = LoginForm.get_form()
|
|
|
|
# Simple admin site placeholders that will be replaced after Django setup
|
|
class AdminSitePlaceholder(UnfoldAdminSite):
|
|
"""Placeholder that behaves like an admin site until Django is fully loaded"""
|
|
|
|
def __init__(self, site_class, name):
|
|
# Initialize with minimal setup to avoid circular imports
|
|
self._site_class = site_class
|
|
self._name = name
|
|
self._real_instance = None
|
|
# Don't call super().__init__() here to avoid circular imports
|
|
|
|
def _get_real_instance(self):
|
|
if self._real_instance is None:
|
|
self._real_instance = self._site_class(name=self._name)
|
|
return self._real_instance
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self._get_real_instance(), name)
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
return self._get_real_instance()(*args, **kwargs)
|
|
|
|
# Create placeholder instances
|
|
project_admin_site = AdminSitePlaceholder(FormulaAdminSite, 'imam_javad_admin')
|
|
dovoodi_admin_site = AdminSitePlaceholder(DovoodiAdminSite, 'dovoodi_admin')
|
|
|
|
class HomeView(RedirectView):
|
|
pattern_name = "imam_javad_admin:index"
|
|
|
|
# ---------------------------------------------------------
|
|
# 4. Dummy Data for Dashboard Charts
|
|
# ---------------------------------------------------------
|
|
|
|
@lru_cache
|
|
def random_data():
|
|
WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
|
|
|
# Generate some fake data
|
|
positive = [[1, random.randrange(8, 28)] for i in range(1, 28)]
|
|
negative = [[-1, -random.randrange(8, 28)] for i in range(1, 28)]
|
|
average = [r[1] - random.randint(3, 5) for r in positive]
|
|
performance_positive = [[1, random.randrange(8, 28)] for i in range(1, 28)]
|
|
performance_negative = [[-1, -random.randrange(8, 28)] for i in range(1, 28)]
|
|
|
|
return {
|
|
"navigation": [
|
|
{"title": _("Dashboard"), "link": "/", "active": True},
|
|
{"title": _("Analytics"), "link": "#"},
|
|
{"title": _("Settings"), "link": "#"},
|
|
],
|
|
"kpi": [
|
|
{
|
|
"title": "Total Revenue",
|
|
"metric": f"${intcomma(f'{random.uniform(1000, 9999):.02f}')}",
|
|
"footer": mark_safe(f'<strong class="text-green-700 font-semibold dark:text-green-400">+{intcomma(f"{random.uniform(1, 9):.02f}")}%</strong> progress'),
|
|
"chart": json.dumps({"labels": [WEEKDAYS[day % 7] for day in range(1, 28)], "datasets": [{"data": average, "borderColor": "#9333ea"}]}),
|
|
},
|
|
],
|
|
"chart": json.dumps({
|
|
"labels": [WEEKDAYS[day % 7] for day in range(1, 28)],
|
|
"datasets": [
|
|
{"label": "Revenue", "data": positive, "backgroundColor": "var(--color-primary-700)"},
|
|
],
|
|
}),
|
|
}
|