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

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Management Console
#  Mixins for UMC 2.0 modules
#
# Copyright 2013-2022 Univention GmbH
#
# https://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
# <https://www.gnu.org/licenses/>.

"""
Mixins for UMC module classes
=============================

This module provides some mixins that can be incorporated in existing UMC
modules. These mixins extend the functionality of the module in an easy-to-use
way. Just let your module derive from
:class:`~univention.management.console.module.Base` (as before) and the mixin
classes.
"""
import random

import six

from univention.lib.i18n import Translation
from univention.management.console.error import BadRequest
from univention.management.console.modules.decorators import simple_response

_ = Translation('univention-management-console').translate


[docs]class Progress(object): """ Class to keep track of the progress during execution of a function. Used internally. """ def __init__(self, progress_id, title, total): self.id = progress_id self.title = title self.message = '' self.current = 0.0 self.total = total self.intermediate = [] self.finished = False self.exc_info = None self.retry_after = 200 self.location = None # there is another variable named # "result". it is only set if explicitly # calling finish_with_result
[docs] def progress(self, detail=None, message=None): self.current += 1 self.intermediate.append(detail) if message is not None: self.message = message
[docs] def finish(self): if self.finished: return False self.finished = True return True
[docs] def finish_with_result(self, result): if self.finish(): self.result = result
[docs] def initialised(self): return {'id': self.id, 'title': self.title}
[docs] def exception(self, exc_info): self.exc_info = exc_info
[docs] def poll(self): if self.exc_info: self.finish() six.reraise(*self.exc_info) ret = { 'title': self.title, 'finished': self.finished, 'intermediate': self.intermediate[:], 'message': self.message, 'retry_after': self.retry_after, } try: ret['percentage'] = self.current / self.total * 100 except ZeroDivisionError: # ret['percentage'] = float('Infinity') FIXME: JSON cannot handle Infinity ret['percentage'] = 'Infinity' if self.location is not None: ret['location'] = self.location if hasattr(self, 'result'): ret['result'] = self.result del self.intermediate[:] return ret
[docs]class ProgressMixin(object): """ Mixin to provide two new functions: * *new_progress* to create a new :class:`~univention.management.console.modules.mixins.Progress`. * *progress* to let the client fetch the progress made up to this moment. The *progress* function needs to be made public by the XML definition of the module. To use this mixin, just do:: class Instance(Base, ProgressMixin): pass """
[docs] def new_progress(self, title=None, total=0): if not hasattr(self, '_progress_id'): self._progress_id = 0 if not hasattr(self, '_progress_objs'): self._progress_objs = {} if title is None: title = _('Please wait for operation to finish') self._progress_id += random.randint(1, 100000) self._progress_objs[self._progress_id] = progress = Progress(self._progress_id, title, total) return progress
[docs] @simple_response def progress(self, progress_id): if not hasattr(self, '_progress_objs'): self._progress_objs = {} try: progress_obj = self._progress_objs[progress_id] except KeyError: raise BadRequest(_('Invalid progress ID')) else: ret = progress_obj.poll() if ret['finished']: del self._progress_objs[progress_id] return ret