summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2023-02-23 18:09:15 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2023-02-23 18:11:08 +0100
commit2ae0e6f81e570a75ac27d455db9834c93f66d1fe (patch)
treeade5f9523698ad0ec5bcf988834f73df8d140dc3 /ishtar_common
parentd86abf7eb1d5a7ea8c8c0ecfde24680d3a5d7094 (diff)
downloadIshtar-2ae0e6f81e570a75ac27d455db9834c93f66d1fe.tar.bz2
Ishtar-2ae0e6f81e570a75ac27d455db9834c93f66d1fe.zip
Admin: overload index to add sub-section headers
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/apps.py105
-rw-r--r--ishtar_common/models.py60
-rw-r--r--ishtar_common/models_common.py8
-rw-r--r--ishtar_common/models_imports.py47
-rw-r--r--ishtar_common/models_rest.py5
-rw-r--r--ishtar_common/templates/admin/index.html91
6 files changed, 287 insertions, 29 deletions
diff --git a/ishtar_common/apps.py b/ishtar_common/apps.py
index eca70b3e1..1f076462d 100644
--- a/ishtar_common/apps.py
+++ b/ishtar_common/apps.py
@@ -1,5 +1,7 @@
-from django.apps import AppConfig
+from django.apps import AppConfig, apps
from django.contrib.admin import AdminSite
+from django.urls import NoReverseMatch, reverse
+from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
@@ -7,6 +9,107 @@ class IshtarAdminSite(AdminSite):
site_header = _("Ishtar administration")
site_title = _("Ishtar administration")
+ MODEL_OVERLOAD = {
+ # (app, model) -> new app
+ ("ishtar_common", "OperationType"): "archaeological_operations"
+ }
+
+ def _build_app_dict(self, request, label=None):
+ # copied from contrib/admin/sites.py
+ # overload to get add "admin_section" in models and use MODEL_OVERLOAD
+ app_dict = {}
+
+ if label:
+ models = {
+ m: m_a for m, m_a in self._registry.items()
+ if m._meta.app_label == label or self.MODEL_OVERLOAD.get(
+ (m._meta.app_label, m._meta.object_name), None
+ )
+ }
+ else:
+ models = self._registry
+
+ for model, model_admin in models.items():
+ app_label = model._meta.app_label
+ # Ishtar
+ object_name = model._meta.object_name
+ if (app_label, object_name) in self.MODEL_OVERLOAD:
+ app_label_for_dict = self.MODEL_OVERLOAD[(app_label, object_name)]
+ else:
+ app_label_for_dict = app_label
+ # end Ishtar
+
+ has_module_perms = model_admin.has_module_permission(request)
+ if not has_module_perms:
+ continue
+
+ perms = model_admin.get_model_perms(request)
+
+ # Check whether user has any perm for this module.
+ # If so, add the module to the model_list.
+ if True not in perms.values():
+ continue
+
+
+ info = (app_label, model._meta.model_name)
+ model_dict = {
+ 'name': capfirst(model._meta.verbose_name_plural),
+ 'object_name': model._meta.object_name,
+ 'perms': perms,
+ 'admin_url': None,
+ 'add_url': None,
+ # Ishtar change
+ 'admin_section': getattr(model, "ADMIN_SECTION", ""),
+ # End Ishtar change
+ }
+ if perms.get('change') or perms.get('view'):
+ model_dict['view_only'] = not perms.get('change')
+ try:
+ model_dict['admin_url'] = reverse('admin:%s_%s_changelist' % info,
+ current_app=self.name)
+ except NoReverseMatch:
+ pass
+ if perms.get('add'):
+ try:
+ model_dict['add_url'] = reverse('admin:%s_%s_add' % info,
+ current_app=self.name)
+ except NoReverseMatch:
+ pass
+ # Ishtar
+ if app_label_for_dict in app_dict:
+ app_dict[app_label_for_dict]['models'].append(model_dict)
+ else:
+ app_dict[app_label_for_dict] = {
+ 'name': apps.get_app_config(app_label_for_dict).verbose_name,
+ 'app_label': app_label_for_dict,
+ 'app_url': reverse(
+ 'admin:app_list',
+ kwargs={'app_label': app_label_for_dict},
+ current_app=self.name,
+ ),
+ 'has_module_perms': has_module_perms,
+ 'models': [model_dict],
+ }
+ # Ishtar end
+
+ if label:
+ return app_dict.get(label)
+ return app_dict
+
+ def get_app_list(self, request):
+ # copied from contrib/admin/sites.py
+ # overload to sort models by "admin_section"
+ app_dict = self._build_app_dict(request)
+
+ # Sort the apps alphabetically.
+ app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())
+
+ # Sort the models alphabetically within each app.
+ for app in app_list:
+ app['models'].sort(key=lambda x: (x['admin_section'], x['name'])) # Ishtar change
+
+ return app_list
+
admin_site = IshtarAdminSite()
# AFAC
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 83ca5129b..e4f13ab5f 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -49,7 +49,6 @@ from xml.etree import ElementTree as ET
from django.apps import apps
from django.conf import settings
from django.contrib.auth.models import User, Group
-from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.gis.db import models
from django.contrib.gis.db.models.aggregates import Union
@@ -117,6 +116,7 @@ from ishtar_common.models_imports import (
Import,
TargetKeyGroup,
ValueFormater,
+ ItemKey,
)
from ishtar_common.utils import (
@@ -177,6 +177,7 @@ __all__ = [
"ImporterDuplicateField",
"Regexp",
"ImportTarget",
+ "ItemKey",
"TargetKey",
"FormaterType",
"Import",
@@ -447,29 +448,6 @@ class TinyUrl(models.Model):
return i
-class ItemKey(models.Model):
- key = models.TextField(_("Key"))
- content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
- object_id = models.PositiveIntegerField()
- content_object = GenericForeignKey("content_type", "object_id")
- importer = models.ForeignKey(
- Import,
- null=True,
- blank=True,
- help_text=_("Specific key to an import"),
- on_delete=models.SET_NULL,
- )
- user = models.ForeignKey(
- "IshtarUser", blank=True, null=True, on_delete=models.SET_NULL
- )
- group = models.ForeignKey(
- TargetKeyGroup, blank=True, null=True, on_delete=models.SET_NULL
- )
-
- def __str__(self):
- return self.key
-
-
class ImageModel(models.Model, ImageContainerModel):
image = models.ImageField(
upload_to=get_image_path,
@@ -698,6 +676,7 @@ class JsonDataSection(models.Model):
verbose_name_plural = _("Custom data - Menus")
ordering = ["order", "name"]
unique_together = ("name", "content_type")
+ ADMIN_SECTION = _("Custom data / custom forms")
def natural_key(self):
return (self.name, self.content_type.app_label, self.content_type.model)
@@ -761,6 +740,7 @@ class JsonDataField(models.Model):
verbose_name_plural = _("Custom data - Fields")
ordering = ["order", "name"]
unique_together = ("content_type", "key")
+ ADMIN_SECTION = _("Custom data / custom forms")
def natural_key(self):
return (self.key, self.content_type.app_label, self.content_type.model)
@@ -1000,6 +980,7 @@ class Language(GeneralType):
class Meta:
verbose_name = _("Language")
verbose_name_plural = _("Languages")
+ ADMIN_SECTION = _("Documents")
CURRENCY = (("€", _("Euro")), ("$", _("US dollar")))
@@ -1542,6 +1523,7 @@ class IshtarSiteProfile(models.Model, Cached):
verbose_name = _("Ishtar site profile")
verbose_name_plural = _("Ishtar site profiles")
ordering = ["label"]
+ ADMIN_SECTION = _("General settings")
def __str__(self):
return str(self.label)
@@ -1667,6 +1649,7 @@ class CustomForm(models.Model):
verbose_name_plural = _("Custom forms")
ordering = ["name", "form"]
unique_together = (("name", "form"),)
+ ADMIN_SECTION = _("Custom data / custom forms")
def natural_key(self):
return (self.name, self.form)
@@ -1815,9 +1798,10 @@ class CustomFormJsonField(models.Model):
objects = CustomFormJsonFieldManager()
class Meta:
- verbose_name = _("Custom form - Json data field")
- verbose_name_plural = _("Custom form - Json data fields")
+ verbose_name = _("Custom forms - Json data field")
+ verbose_name_plural = _("Custom forms - Json data fields")
unique_together = ("custom_form", "json_field")
+ ADMIN_SECTION = _("Custom data / custom forms")
def natural_key(self):
return (
@@ -1841,6 +1825,7 @@ class GlobalVar(models.Model, Cached):
verbose_name = _("Global variable")
verbose_name_plural = _("Global variables")
ordering = ["slug"]
+ ADMIN_SECTION = _("General settings")
def natural_key(self):
return (self.slug,)
@@ -2063,6 +2048,7 @@ class DocumentTemplate(models.Model):
verbose_name = _("Document template")
verbose_name_plural = _("Document templates")
ordering = ["associated_model", "name"]
+ ADMIN_SECTION = _("General settings")
def __str__(self):
return self.name
@@ -2363,6 +2349,7 @@ class Area(HierarchicalType):
verbose_name = _("Town - Area")
verbose_name_plural = _("Town - Areas")
ordering = ("label",)
+ ADMIN_SECTION = _("Geography")
def __str__(self):
if not self.reference:
@@ -2492,6 +2479,7 @@ class OrganizationType(GenderedType):
verbose_name = _("Organization type")
verbose_name_plural = _("Organization types")
ordering = ("label",)
+ ADMIN_SECTION = _("Directory")
def get_orga_planning_service_label():
@@ -2591,6 +2579,7 @@ class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter, Main
indexes = [
GinIndex(fields=["data"]),
]
+ ADMIN_SECTION = _("Directory")
def simple_lbl(self):
if self.name:
@@ -2644,6 +2633,7 @@ class PersonType(GeneralType):
verbose_name = _("Person type")
verbose_name_plural = _("Person types")
ordering = ("label",)
+ ADMIN_SECTION = _("Directory")
post_save.connect(post_save_cache, sender=PersonType)
@@ -2717,6 +2707,7 @@ class TitleType(GenderedType):
verbose_name = _("Title type")
verbose_name_plural = _("Title types")
ordering = ("label",)
+ ADMIN_SECTION = _("Directory")
@classmethod
def get_documentation_string(cls):
@@ -2886,6 +2877,7 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
("delete_own_person", "Can delete own Person"),
)
ordering = ['name', 'surname']
+ ADMIN_SECTION = _("Directory")
def natural_key(self):
return (self.uuid,)
@@ -3165,6 +3157,7 @@ class ProfileType(GeneralType):
verbose_name = _("Profile type")
verbose_name_plural = _("Profile types")
ordering = ("label",)
+ ADMIN_SECTION = _("Directory")
post_save.connect(post_save_cache, sender=ProfileType)
@@ -3176,6 +3169,7 @@ class ProfileTypeSummary(ProfileType):
proxy = True
verbose_name = _("Profile type summary")
verbose_name_plural = _("Profile types summary")
+ ADMIN_SECTION = _("Directory")
class UserProfile(models.Model):
@@ -3212,6 +3206,7 @@ class UserProfile(models.Model):
verbose_name = _("User profile")
verbose_name_plural = _("User profiles")
unique_together = (("name", "profile_type", "person"),)
+ ADMIN_SECTION = _("Directory")
def __str__(self):
lbl = self.name or str(self.profile_type)
@@ -3407,6 +3402,7 @@ class IshtarUser(FullSearch):
class Meta:
verbose_name = _("Ishtar user")
verbose_name_plural = _("Ishtar users")
+ ADMIN_SECTION = _("Directory")
def __str__(self):
return str(self.person)
@@ -3620,6 +3616,7 @@ class AuthorType(GeneralType):
verbose_name = _("Author type")
verbose_name_plural = _("Author types")
ordering = ["order", "label"]
+ ADMIN_SECTION = _("Directory")
post_save.connect(post_save_cache, sender=AuthorType)
@@ -3655,6 +3652,7 @@ class Author(FullSearch):
("change_own_author", "Can change own Author"),
("delete_own_author", "Can delete own Author"),
)
+ ADMIN_SECTION = _("Directory")
def __str__(self):
return self.cached_label or ""
@@ -3717,6 +3715,7 @@ class SourceType(HierarchicalType):
verbose_name = _("Document type")
verbose_name_plural = _("Document types")
ordering = ["label"]
+ ADMIN_SECTION = _("Documents")
post_save.connect(post_save_cache, sender=SourceType)
@@ -3734,6 +3733,7 @@ class SupportType(GeneralType):
class Meta:
verbose_name = _("Support type")
verbose_name_plural = _("Support types")
+ ADMIN_SECTION = _("Documents")
post_save.connect(post_save_cache, sender=SupportType)
@@ -3762,6 +3762,7 @@ class Format(GeneralType):
verbose_name = _("Format type")
verbose_name_plural = _("Format types")
ordering = ["label"]
+ ADMIN_SECTION = _("Documents")
post_save.connect(post_save_cache, sender=Format)
@@ -3775,6 +3776,7 @@ class LicenseType(GeneralType):
verbose_name = _("License type")
verbose_name_plural = _("License types")
ordering = ("label",)
+ ADMIN_SECTION = _("Documents")
class DocumentTag(GeneralType):
@@ -3784,6 +3786,7 @@ class DocumentTag(GeneralType):
verbose_name = _("Document tag")
verbose_name_plural = _("Document tags")
ordering = ("label",)
+ ADMIN_SECTION = _("Documents")
post_save.connect(post_save_cache, sender=LicenseType)
@@ -4304,6 +4307,7 @@ class Document(
indexes = [
GinIndex(fields=["data"]),
]
+ ADMIN_SECTION = _("Documents")
def __str__(self):
return self.title
@@ -5033,6 +5037,7 @@ class AdministrationScript(models.Model):
verbose_name = _("Administration script")
verbose_name_plural = _("Administration scripts")
ordering = ["name"]
+ ADMIN_SECTION = _("General settings")
def __str__(self):
return str(self.name)
@@ -5062,6 +5067,7 @@ class AdministrationTask(models.Model):
verbose_name = _("Administration task")
verbose_name_plural = _("Administration tasks")
ordering = ["script"]
+ ADMIN_SECTION = _("General settings")
def __str__(self):
state = _("Unknown")
@@ -5219,6 +5225,7 @@ class ExportTask(models.Model):
verbose_name = _("Archive - Export")
verbose_name_plural = _("Archive - Exports")
ordering = ["creation_date"]
+ ADMIN_SECTION = pgettext_lazy("name", "Archive")
def __str__(self):
state = _("Unknown")
@@ -5278,6 +5285,7 @@ class ImportTask(models.Model):
verbose_name = _("Archive - Import")
verbose_name_plural = _("Archive - Imports")
ordering = ["creation_date"]
+ ADMIN_SECTION = pgettext_lazy("name", "Archive")
def __str__(self):
state = _("Unknown")
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index bc078df1c..fc73d707c 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -2008,6 +2008,7 @@ class Department(models.Model):
verbose_name = _("Department")
verbose_name_plural = _("Departments")
ordering = ["number"]
+ ADMIN_SECTION = _("Geography")
def __str__(self):
return self.label
@@ -2063,6 +2064,7 @@ class SpatialReferenceSystem(GeneralType):
"order",
"label",
)
+ ADMIN_SECTION = _("Geography")
@classmethod
def get_documentation_string(cls):
@@ -2094,6 +2096,7 @@ class GeoOriginType(HierarchicalType):
"order",
"label",
)
+ ADMIN_SECTION = _("Geography")
class GeoDataType(HierarchicalType):
@@ -2110,6 +2113,7 @@ class GeoDataType(HierarchicalType):
"order",
"label",
)
+ ADMIN_SECTION = _("Geography")
class GeoProviderType(HierarchicalType):
@@ -2126,6 +2130,7 @@ class GeoProviderType(HierarchicalType):
"order",
"label",
)
+ ADMIN_SECTION = _("Geography")
class GeoBufferType(GeneralType):
@@ -2138,6 +2143,7 @@ class GeoBufferType(GeneralType):
"order",
"label",
)
+ ADMIN_SECTION = _("Geography")
GEOJSON_POINT_TPL = {
@@ -2266,6 +2272,7 @@ class GeoVectorData(Imported, OwnPerms):
("change_own_geovectordata", "Can change own Geographic - Vector data"),
("delete_own_geovectordata", "Can delete own Geographic - Vector data"),
)
+ ADMIN_SECTION = _("Geography")
def __str__(self):
name = self.name
@@ -2950,6 +2957,7 @@ class Town(GeographicItem, Imported, models.Model):
if settings.COUNTRY == "fr":
ordering = ["numero_insee"]
unique_together = (("numero_insee", "year"),)
+ ADMIN_SECTION = _("Geography")
def natural_key(self):
return (self.numero_insee, self.year)
diff --git a/ishtar_common/models_imports.py b/ishtar_common/models_imports.py
index 33463e181..6451206a2 100644
--- a/ishtar_common/models_imports.py
+++ b/ishtar_common/models_imports.py
@@ -33,6 +33,8 @@ import zipfile
from django.apps import apps
from django.conf import settings
+from django.contrib.contenttypes.fields import GenericForeignKey
+from django.contrib.contenttypes.models import ContentType
from django.contrib.gis.db import models
from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.geos import GEOSGeometry
@@ -112,9 +114,10 @@ class ImporterModel(models.Model):
objects = ImportModelManager()
class Meta:
- verbose_name = _("Model")
- verbose_name_plural = _("Models")
+ verbose_name = _("Data model")
+ verbose_name_plural = _("Data models")
ordering = ("name",)
+ ADMIN_SECTION = _("General settings")
def __str__(self):
return self.name
@@ -192,6 +195,7 @@ class ImporterType(models.Model):
verbose_name = _("Importer - Type")
verbose_name_plural = _("Importer - Types")
ordering = ("name",)
+ ADMIN_SECTION = _("Imports")
def natural_key(self):
return (self.slug,)
@@ -439,6 +443,7 @@ class ImporterDefault(models.Model):
verbose_name = _("Importer - Default")
verbose_name_plural = _("Importer - Defaults")
unique_together = ("importer_type", "target")
+ ADMIN_SECTION = _("Imports")
objects = ImporterDefaultManager()
@@ -496,6 +501,7 @@ class ImporterDefaultValues(models.Model):
verbose_name = _("Importer - Default value")
verbose_name_plural = _("Importer - Default values")
unique_together = ("default_target", "target")
+ ADMIN_SECTION = _("Imports")
def natural_key(self):
return (
@@ -602,6 +608,7 @@ class ImporterColumn(models.Model):
verbose_name_plural = _("Importer - Columns")
ordering = ("importer_type", "col_number")
unique_together = ("importer_type", "col_number")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return "{} - {}".format(self.importer_type, self.col_number)
@@ -655,6 +662,7 @@ class ImporterDuplicateField(models.Model):
verbose_name_plural = _("Importer - Duplicate fields")
ordering = ("column", "field_name")
unique_together = ("column", "field_name")
+ ADMIN_SECTION = _("Imports")
def natural_key(self):
return self.column.importer_type.slug, self.column.col_number, self.field_name
@@ -674,6 +682,7 @@ class Regexp(models.Model):
class Meta:
verbose_name = _("Importer - Regular expression")
verbose_name_plural = _("Importer - Regular expressions")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return self.name
@@ -702,6 +711,7 @@ class ValueFormater(models.Model):
class Meta:
verbose_name = _("Importer - Value format")
verbose_name_plural = _("Importer - Value formats")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return self.name
@@ -755,6 +765,7 @@ class ImportTarget(models.Model):
verbose_name = _("Importer - Target")
verbose_name_plural = _("Importer - Targets")
unique_together = ("column", "target")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return self.target[:50] if self.target else self.comment
@@ -814,6 +825,7 @@ class TargetKeyGroup(models.Model):
class Meta:
verbose_name = _("Importer - Target key group")
verbose_name_plural = _("Importer - Target key groups")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return self.name
@@ -856,6 +868,7 @@ class TargetKey(models.Model):
verbose_name = _("Importer - Target key")
verbose_name_plural = _("Importer - Targets keys")
ordering = ("target", "key")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return " - ".join([str(self.target), self.key[:50]])
@@ -1034,6 +1047,7 @@ class FormaterType(models.Model):
verbose_name_plural = _("Importer - Formater types")
unique_together = ("formater_type", "options", "many_split")
ordering = ("formater_type", "options")
+ ADMIN_SECTION = _("Imports")
def natural_key(self):
return self.formater_type, self.options, self.many_split
@@ -1284,6 +1298,7 @@ class Import(models.Model):
class Meta:
verbose_name = _("Import")
verbose_name_plural = _("Imports")
+ ADMIN_SECTION = _("Imports")
def __str__(self):
return "{} | {}".format(self.name or "-", self.importer_type)
@@ -1916,3 +1931,31 @@ def pre_delete_import(sender, **kwargs):
pre_delete.connect(pre_delete_import, sender=Import)
+
+
+class ItemKey(models.Model):
+ key = models.TextField(_("Key"))
+ content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
+ object_id = models.PositiveIntegerField()
+ content_object = GenericForeignKey("content_type", "object_id")
+ importer = models.ForeignKey(
+ Import,
+ null=True,
+ blank=True,
+ help_text=_("Specific key to an import"),
+ on_delete=models.SET_NULL,
+ )
+ user = models.ForeignKey(
+ "IshtarUser", blank=True, null=True, on_delete=models.SET_NULL
+ )
+ group = models.ForeignKey(
+ TargetKeyGroup, blank=True, null=True, on_delete=models.SET_NULL
+ )
+
+ class Meta:
+ verbose_name = _("Importer - Item key")
+ verbose_name_plural = _("Imports - Item keys")
+ ADMIN_SECTION = _("Imports")
+
+ def __str__(self):
+ return self.key
diff --git a/ishtar_common/models_rest.py b/ishtar_common/models_rest.py
index 5737ec368..411404325 100644
--- a/ishtar_common/models_rest.py
+++ b/ishtar_common/models_rest.py
@@ -51,6 +51,7 @@ class ApiUser(models.Model):
class Meta:
verbose_name = _("API - Remote access - User")
verbose_name_plural = _("API - Remote access - Users")
+ ADMIN_SECTION = _("API")
def __str__(self):
return self.user_ptr.username
@@ -77,6 +78,7 @@ class ApiSearchModel(models.Model):
class Meta:
verbose_name = _("API - Remote access - Search model")
verbose_name_plural = _("API - Remote access - Search models")
+ ADMIN_SECTION = _("API")
def __str__(self):
return f"{self.user} - {self.content_type}"
@@ -89,6 +91,7 @@ class ApiSheetFilter(SheetFilter):
class Meta:
verbose_name = _("API - Remote access - Sheet filter")
verbose_name_plural = _("API - Remote access - Sheet filters")
+ ADMIN_SECTION = _("API")
def get_template(self):
ct = self.api_search_model.content_type
@@ -125,6 +128,7 @@ class ApiExternalSource(models.Model):
verbose_name = _("API - Search - External source")
verbose_name_plural = _("API - Search - External sources")
ordering = ("name",)
+ ADMIN_SECTION = _("API")
def __str__(self):
return self.name
@@ -435,3 +439,4 @@ class ApiKeyMatch(models.Model):
class Meta:
verbose_name = _("API - Search - Key match")
verbose_name_plural = _("API - Search - Keys matches")
+ ADMIN_SECTION = _("API")
diff --git a/ishtar_common/templates/admin/index.html b/ishtar_common/templates/admin/index.html
new file mode 100644
index 000000000..1019ea7c0
--- /dev/null
+++ b/ishtar_common/templates/admin/index.html
@@ -0,0 +1,91 @@
+{% extends "admin/base_site.html" %}
+{% load i18n static %}
+
+{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}">{% endblock %}
+
+{% block coltype %}colMS{% endblock %}
+
+{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+<div id="content-main">
+
+{% if app_list %}
+ {% for app in app_list %}
+ <div class="app-{{ app.app_label }} module">
+ <table>
+ <caption>
+ <a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
+ </caption>
+ {% for model in app.models %}
+ {# Ishtar #}
+ {% ifchanged model.admin_section %}
+ {% if model.admin_section or forloop.counter0 %}<tr><th colspan="3">{% if model.admin_section %}{{ model.admin_section }}{% else %}&nbsp;{% endif %}</th></tr>{% endif %}
+ {% endifchanged %}
+ {# Ishtar end #}
+ <tr class="model-{{ model.object_name|lower }}">
+ {% if model.admin_url %}
+ <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
+ {% else %}
+ <th scope="row">{{ model.name }}</th>
+ {% endif %}
+
+ {% if model.add_url %}
+ <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
+ {% else %}
+ <td>&nbsp;</td>
+ {% endif %}
+
+ {% if model.admin_url %}
+ {% if model.view_only %}
+ <td><a href="{{ model.admin_url }}" class="viewlink">{% trans 'View' %}</a></td>
+ {% else %}
+ <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
+ {% endif %}
+ {% else %}
+ <td>&nbsp;</td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endfor %}
+{% else %}
+ <p>{% trans "You don't have permission to view or edit anything." %}</p>
+{% endif %}
+</div>
+{% endblock %}
+
+{% block sidebar %}
+<div id="content-related">
+ <div class="module" id="recent-actions-module">
+ <h2>{% trans 'Recent actions' %}</h2>
+ <h3>{% trans 'My actions' %}</h3>
+ {% load log %}
+ {% get_admin_log 10 as admin_log for_user user %}
+ {% if not admin_log %}
+ <p>{% trans 'None available' %}</p>
+ {% else %}
+ <ul class="actionlist">
+ {% for entry in admin_log %}
+ <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
+ {% if entry.is_deletion or not entry.get_admin_url %}
+ {{ entry.object_repr }}
+ {% else %}
+ <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
+ {% endif %}
+ <br>
+ {% if entry.content_type %}
+ <span class="mini quiet">{% filter capfirst %}{{ entry.content_type }}{% endfilter %}</span>
+ {% else %}
+ <span class="mini quiet">{% trans 'Unknown content' %}</span>
+ {% endif %}
+ </li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ </div>
+</div>
+{% endblock %}