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

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Management Console module:
#   Get csv class lists
#
# Copyright 2018-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/>.

import csv
import os
import uuid
from datetime import datetime
from io import StringIO

from ldap.dn import explode_rdn
from six.moves.urllib_parse import quote

from ucsschool.lib.models.user import User
from ucsschool.lib.school_umc_base import SchoolBaseModule
from ucsschool.lib.school_umc_ldap_connection import LDAP_Connection
from univention.lib.i18n import Translation
from univention.management.console.config import ucr
from univention.management.console.log import MODULE
from univention.management.console.modules import UMC_Error
from univention.management.console.modules.decorators import allow_get_request, sanitize
from univention.management.console.modules.sanitizers import (
    StringSanitizer,
)

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


[docs] def write_classlist_csv(fieldnames, students, separator): with StringIO() as csvfile: writer = csv.writer(csvfile, delimiter=str(separator)) writer.writerow(fieldnames) for row in students: writer.writerow(row) return csvfile.getvalue()
[docs] class Instance(SchoolBaseModule):
[docs] @allow_get_request @sanitize(classlist=StringSanitizer(required=True)) def csv_get(self, request): classlist = request.options["classlist"] path = "/usr/share/ucs-school-umc-lists/classlists/" filename = os.path.join(path, os.path.basename(classlist)) # Bug #57018 - retrieve charset from filename charset = "utf-16" if "UTF-16" in filename else "utf-8" try: with open(filename, "rb") as fd: self.finished(request.id, fd.read(), mimetype=('text/csv; charset="%s"' % charset)) except EnvironmentError: raise UMC_Error( _("The class list does not exists. Please create a new one."), status=404, )
[docs] @LDAP_Connection() def csv_list(self, request, ldap_user_read=None, ldap_position=None): school = request.options["school"] group = request.options["group"] separator = request.options["separator"] exclude_deactivated = request.options["exclude_deactivated"] default = "firstname Firstname,lastname Lastname,Class Class,username Username" ucr_value = ucr.get("ucsschool/umc/lists/class/attributes", "") or default attributes, fieldnames = zip(*[field.split() for field in ucr_value.split(",")]) rows = [] for student in self.students(ldap_user_read, school, group): if exclude_deactivated and not student.is_active(): continue row = [] student_udm_obj = student.get_udm_object(ldap_user_read) if school not in student.school_classes: MODULE.error( "Student missing class in school {!r}: {!r}".format(school, student_udm_obj.dn) ) continue for attr in attributes: if attr == "Class": row.append(student.school_classes[school][0].split("-", 1)[1]) else: try: value = student_udm_obj[attr] except KeyError: raise UMC_Error( _( "{!r} is not a valid UDM-property. Please change the value of the UCR " "variable ucsschool/umc/lists/class/attributes." ).format(attr) ) if isinstance(value, list): value = " ".join(value) row.append(value) rows.append(row) classlistname = explode_rdn(group, True)[0] timestamp = datetime.now().strftime("%Y-%m-%d_%H_%M_%S") # Bug #57018 - workaround to pass used encoding in filename enc = "UTF-16" if separator == "\t" else "UTF-8" filename = "%s_%s_%s-%s.csv" % (classlistname.replace("/", "_"), enc, timestamp, uuid.uuid4()) path = os.path.join("/usr/share/ucs-school-umc-lists/classlists/", filename) with open(path, "w", encoding=enc) as fd: os.chmod(path, 0o600) fd.write(write_classlist_csv(fieldnames, rows, separator)) url = "/univention/command/schoollists/csvlistget?classlist=%s" % (quote(filename),) self.finished( request.id, { "url": url, "filename": "{}_{}.csv".format(classlistname.replace("/", "_"), timestamp), }, )
[docs] def students(self, lo, school, group): for user in self._users(lo, school, group=group, user_type="student"): yield User.from_udm_obj(user, school, lo)