Source code for univention.management.console.category

#
# Univention Management Console
#  UMC category definitions
#
# SPDX-FileCopyrightText: 2006-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

"""
Category definitions
====================

The UMC server provides the possibility to define categories used to
sort the available UMC modules into groups. Each module can be in as
many groups as desired.

The category definitions are stored in XML files that structured as in
the following example

.. code-block:: xml

    <?xml version="1.0" encoding="UTF-8"?>
    <umc version="2.0">
        <categories>
            <category id="id1">
                <name>Category 1</name>
            </category>
            <category id="id2">
                <name>Category 2 on {hostname}.{domainname}</name>
            </category>
        </categories>
    </umc>

Each file can define several categories. For each of these
categories an unique identifier and the english description must be
specified. The translations are stored in extra po files that are
generated by the UMC build tools.

Within the description of a category UCR variable names can be used that
will be substituted by the value. Therefore the name of the variables
must be given in curly braces {VARIABLE}.
"""

import os
import sys
import xml.etree.ElementTree as ET  # noqa: S405
import xml.parsers.expat

from .log import RESOURCES


[docs] class XML_Definition(ET.ElementTree): """Represents a category definition.""" def __init__(self, root=None, filename=None, domain=None): ET.ElementTree.__init__(self, element=root, file=filename) self.domain = domain @property def name(self): """Returns the descriptive name of the category""" return self.find('name').text @property def id(self): """Returns the unique identifier of the category""" return self._root.get('id') @property def icon(self): return self._root.get('icon') @property def color(self): return self._root.get('color') @property def priority(self): """ Returns the priority of the category. If no priority is defined the default priority of -1 is returned. None is returned if the specified priority is not a valid float :rtype: float or None """ try: return float(self._root.get('priority', -1)) except ValueError: RESOURCES.warning('No valid number type for property "priority": %s', self._root.get('priority')) return None
[docs] def json(self): """ Returns a JSON compatible representation of the category :rtype: dict """ return { 'id': self.id, 'name': self.name, 'icon': self.icon, 'color': self.color, 'priority': self.priority, }
[docs] class Manager(dict): """This class manages all available categories.""" DIRECTORY = os.path.join(sys.prefix, 'share/univention-management-console/categories') def __init__(self): dict.__init__(self)
[docs] def all(self): return [x.json() for x in self.values()]
[docs] def load(self): self.clear() RESOURCES.info('Loading categories ...') for filename in os.listdir(Manager.DIRECTORY): if not filename.endswith('.xml'): RESOURCES.info('Found file %s with wrong suffix', filename) continue try: definitions = ET.ElementTree(file=os.path.join(Manager.DIRECTORY, filename)) categories = definitions.find('categories') if categories is None: continue i18nDomain = categories.get('domain') for category_elem in definitions.findall('categories/category'): category = XML_Definition(root=category_elem, domain=i18nDomain) self[category.id] = category RESOURCES.info('Loaded categories from %s', filename) except (xml.parsers.expat.ExpatError, ET.ParseError) as exc: RESOURCES.warning('Failed to parse category file %s: %s', filename, exc) continue