Source code for univention.management.console.modules.schoolrooms

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Management Console module:
#   Manage room and their associated computers
#
# Copyright 2012-2025 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

from typing import TYPE_CHECKING, List  # noqa: F401

import univention.admin.uexceptions as udm_exceptions
from ucsschool.lib.models.computer import SchoolComputer
from ucsschool.lib.models.group import ComputerRoom
from ucsschool.lib.models.utils import add_module_logger_to_schoollib
from ucsschool.lib.school_umc_base import LDAP_Filter, SchoolBaseModule, SchoolSanitizer
from ucsschool.lib.school_umc_ldap_connection import USER_READ, USER_WRITE, LDAP_Connection
from univention.lib.i18n import Translation
from univention.management.console.modules.decorators import sanitize
from univention.management.console.modules.sanitizers import (
    DictSanitizer,
    DNSanitizer,
    LDAPSearchSanitizer,
    ListSanitizer,
)

if TYPE_CHECKING:
    import univention.admin.uldap.access  # noqa: F401


_ = Translation("ucs-school-umc-rooms").translate


[docs] class Instance(SchoolBaseModule):
[docs] def init(self): super(Instance, self).init() add_module_logger_to_schoollib()
[docs] @sanitize( school=SchoolSanitizer(required=True), pattern=LDAPSearchSanitizer(required=False, default="", use_asterisks=True, add_asterisks=False), ) @LDAP_Connection() def computers(self, request, ldap_user_read=None): pattern = LDAP_Filter.forComputers(request.options.get("pattern", "")) result = [ {"label": x.name, "id": x.dn, "teacher_computer": x.teacher_computer} for x in SchoolComputer.get_all(ldap_user_read, request.options["school"], pattern) ] result = sorted(result, key=lambda x: x["label"]) # TODO: still necessary? self.finished(request.id, result)
[docs] @sanitize( school=SchoolSanitizer(required=True), pattern=LDAPSearchSanitizer(required=False, default="", use_asterisks=True, add_asterisks=False), ) @LDAP_Connection() def query(self, request, ldap_user_read=None): school = request.options["school"] pattern = LDAP_Filter.forGroups( request.options.get("pattern", ""), school, _escape_filter_chars=False, school_prefix=school ) result = [ {"name": x.get_relative_name(), "description": x.description or "", "$dn$": x.dn} for x in ComputerRoom.get_all(ldap_user_read, school, pattern) ] result = sorted(result, key=lambda x: x["name"]) # TODO: still necessary? self.finished(request.id, result)
[docs] @sanitize(DNSanitizer(required=True)) @LDAP_Connection() def get(self, request, ldap_user_read=None): # open the specified room room = ComputerRoom.from_dn(request.options[0], None, ldap_user_read) result = room.to_dict() result["computers"] = result.get("hosts") result["teacher_computers"] = [] for host_dn in result.get("hosts"): host = SchoolComputer.from_dn(host_dn, None, ldap_user_read) # Please remove with Bug #49611 host = SchoolComputer.from_dn(host_dn, None, ldap_user_read) if host.teacher_computer: result["teacher_computers"].append(host_dn) self.finished(request.id, [result])
[docs] @sanitize(DictSanitizer({"object": DictSanitizer({}, required=True)})) @LDAP_Connection(USER_READ, USER_WRITE) def add(self, request, ldap_user_write=None, ldap_user_read=None): """Adds a new room""" group_props = request.options[0].get("object", {}) group_props["hosts"] = group_props.get("computers") room = ComputerRoom(**group_props) if room.get_relative_name() == room.name: room.name = "%(school)s-%(name)s" % group_props room.set_dn(room.dn) success = room.create(ldap_user_write) self._set_teacher_computers( group_props.get("computers", []), group_props.get("teacher_computers", []), ldap_user_read, ldap_user_write, ) self.finished(request.id, [success])
[docs] @sanitize(DictSanitizer({"object": DictSanitizer({}, required=True)})) @LDAP_Connection(USER_READ, USER_WRITE) def put(self, request, ldap_user_write=None, ldap_user_read=None): """Modify an existing room""" group_props = request.options[0].get("object", {}) group_props["hosts"] = group_props.get("computers") room = ComputerRoom(**group_props) # Since we do not have any option on UCS@school 5.0 in the frontend, # we need to retrieve the role from ldap. room.veyon_backend = ComputerRoom.from_dn( lo=ldap_user_read, dn=group_props["$dn$"], school=group_props["school"] ).veyon_backend if room.get_relative_name() == room.name: room.name = "%(school)s-%(name)s" % group_props room.set_dn(group_props["$dn$"]) room.modify(ldap_user_write) self._set_teacher_computers( group_props.get("computers", []), group_props.get("teacher_computers", []), ldap_user_read, ldap_user_write, ) self.finished(request.id, [True])
[docs] @sanitize(DictSanitizer({"object": ListSanitizer(DNSanitizer(required=True), min_elements=1)})) @LDAP_Connection(USER_READ, USER_WRITE) def remove(self, request, ldap_user_write=None, ldap_user_read=None): """Deletes a room""" try: room_dn = request.options[0]["object"][0] room = ComputerRoom.from_dn(room_dn, None, ldap_user_write) room.remove(ldap_user_write) except udm_exceptions.base as e: self.finished(request.id, [{"success": False, "message": str(e)}]) return self.finished(request.id, [{"success": True}])
@staticmethod def _set_teacher_computers( all_computers, # type: List[str] teacher_computers, # type: List[str] ldap_user_read, # type: univention.admin.uldap.access ldap_user_write, # type: univention.admin.uldap.access ): # type (...) -> None """ All computers in teacher_computers become teacher computers. All computers that are in all_computers, but not in teacher_computers become non teacher computers. :param all_computers: All computers present in a room :param teacher_computers: All computers in the room designated to become teacher computers :param ldap_user_read: ldap bind with read access :param ldap_user_write: ldap bind with write access """ # Make teacher computers for computer_dn in teacher_computers: try: # Please remove one call with Bug #49611: computer = SchoolComputer.from_dn(computer_dn, None, ldap_user_write) computer = SchoolComputer.from_dn(computer_dn, None, ldap_user_write) computer.teacher_computer = True computer.modify(ldap_user_write) except udm_exceptions.noObject: pass # Remove teacher computer on deselected non_teacher_computer = set(all_computers).difference(teacher_computers) for computer_dn in non_teacher_computer: try: # Please remove one call with Bug #49611: computer = SchoolComputer.from_dn(computer_dn, None, ldap_user_write) computer = SchoolComputer.from_dn(computer_dn, None, ldap_user_write) computer.teacher_computer = False computer.modify(ldap_user_write) except udm_exceptions.noObject: pass