def dump(scanarium, file):
    local_file = None
    if file == 'dynamic/command-log.json':
        local_file = os.path.join(scanarium.get_dynamic_directory(),
                                  'command-log.json')
    elif file == 'dynamic/config.json':
        local_file = os.path.join(scanarium.get_dynamic_directory(),
                                  'config.json')
    else:
        parts = file.split('/', 3)
        if parts[0:2] == ['dynamic', 'scenes'] and \
                parts[3] in ['actors.json', 'actors-latest.json']:
            parts[2] = re.sub('[^a-zA-Z]', '-', parts[2])
            local_file = os.path.join(scanarium.get_dynamic_directory(),
                                      *parts[1:])

    if local_file is None:
        raise ScanariumError('SE_DYNAMIC_CONFIG_NOT_AVAILABLE',
                             'Dynamic config "{file}" is not available',
                             {'file': file})
    try:
        with open(local_file, 'r') as f:
            return json.load(f)
    except Exception:
        raise ScanariumError('SE_DYNAMIC_CONFIG_UNREADABLE',
                             'Dynamic config "{file}" cannot be read',
                             {'file': file})
示例#2
0
def update_password(scanarium, old_password, new_password):
    pod = os.environ['INSTANCE_NAME']
    username = os.environ['REMOTE_USER']
    stdin = f'{pod}\n{username}\n{old_password}\n{new_password}\n'
    cmd = scanarium.get_config('cgi:update-password', 'delegate')
    try:
        scanarium.run([cmd], input=stdin)
    except ScanariumError as e:
        if e.code == 'SE_RETURN_VALUE':
            stderr_lines = e.private_parameters['stderr'].split('\n')
            if len(stderr_lines) >= 2 \
                    and stderr_lines[-2].startswith('RuntimeError: ') \
                    and stderr_lines[-1] == '':
                msg = stderr_lines[-2][14:]
                raise ScanariumError('SE_PWD_UPDATE_BACKEND_MSG', msg)

            raise ScanariumError('SE_PWD_UPDATE_RETURN_VALUE',
                                 'Backend failed')

        if e.code == 'SE_TIMEOUT':
            raise ScanariumError('SE_PWD_UPDATE_TIMEOUT',
                                 'Update process timed out')

        raise e
    return {}
示例#3
0
def scan_image_no_outer_logging(scanarium):
    image = scanarium.get_image()

    qr_rect = None
    data = None
    iteration = 1
    minimal_width = scanarium.get_config('scan',
                                         'min_raw_width_trip',
                                         kind='int')
    fine_grained_errors = scanarium.get_config('debug',
                                               'fine_grained_errors',
                                               kind='boolean')
    while qr_rect is None:
        try:
            (qr_rect, data) = scanarium.extract_qr(image)
        except ScanariumError as e:
            if e.code == 'SE_SCAN_NO_QR_CODE':
                # QR code could not get scanned. Probably, because the image
                # is too skew. We try to rectify on the images biggest rect
                # (probably the paper sheet). This should undistort the QR
                # code to be scanable in the next round.

                if iteration > 3:
                    if fine_grained_errors:
                        raise ScanariumError(
                            'SE_SCAN_IMAGE_TOO_MANY_ITERATIONS',
                            'Taken too many extraction tries from scanned '
                            'image')
                    else:
                        raise e

                try:
                    image = scanarium.rectify_to_biggest_rect(image)
                except ScanariumError:
                    raise e

                if image.shape[1] < minimal_width:
                    # The image that we're homing in on is really small. It's
                    # unlikely to be a proper A4 image, but rather the camera
                    # did not detect a proper sheet rect and we're homing in on
                    # an (unrelated) small rectangular part of the image. So we
                    # abort.
                    if fine_grained_errors:
                        raise ScanariumError(
                            'SE_SCAN_IMAGE_GREW_TOO_SMALL',
                            'Failed to identify sheet on scanned image')
                    else:
                        raise e
            else:
                raise e

        iteration += 1

    return scanarium.process_image_with_qr_code(image, qr_rect, data)
示例#4
0
 def test_dump_simple_no_file(self):
     dumped = self.run_dump(payload='foo',
                            exc_info=(None,
                                      ScanariumError(
                                          'QUUX', 'QUUUX {xyz}',
                                          {'xyz': 'abc'})),
                            command='bar',
                            parameters=['baz'])
     entry = dumped[0]
     self.assertEqual(entry['command'], 'bar')
     self.assertEqual(entry['parameters'], ['baz'])
     self.assertEqual(entry['payload'], 'foo')
     self.assertEqual(entry['error_code'], 'QUUX')
     self.assertEqual(entry['error_message'], 'QUUUX abc')
     self.assertEqual(entry['error_template'], 'QUUUX {xyz}')
     self.assertEqual(entry['error_parameters'], {'xyz': 'abc'})
     self.assertLenIs(dumped, 1)
示例#5
0
 def _bailout_mode(self, mode):
     mode = mode.strip()
     if mode == 'exit':
         os.kill(os.getpid(), signal.SIGKILL)
     elif mode.startswith('restart-service:'):
         service = re.sub('[^a-zA-Z0-9_-]', '-', mode[16:])
         command = [
             '/usr/bin/sudo', '--non-interactive', '/usr/sbin/service',
             service, 'restart'
         ]
         timeout = self.scanarium.get_config(
             'service:continuous-scanning',
             'bailout_service_restart_timeout',
             kind='int')
         self.scanarium.run(command, timeout=timeout)
     else:
         raise ScanariumError('SE_CONT_SCAN_UNKNOW_BAILOUT',
                              'Unknown bail out method')
示例#6
0
def report_feedback(scanarium, message, email, lastFailedUpload, userAgent):
    target = scanarium.get_config('cgi:report-feedback', 'target')
    if target == 'stderr':
        print(message, file=sys.stderr)
    elif target == 'log':
        filename_base = scanarium.get_log_filename('feedback')
        scanarium.dump_text(filename_base + '.txt', message)
        if email:
            scanarium.dump_text(filename_base + '-email.txt', email)
        if lastFailedUpload:
            img_filename = filename_base + '-last-failed-upload'
            with open(img_filename, 'wb') as f:
                f.write(base64.standard_b64decode(lastFailedUpload))
            format = scanarium.guess_image_format(img_filename)
            if format:
                os.rename(img_filename, f'{img_filename}.{format}')
        if userAgent:
            scanarium.dump_text(filename_base + '-user-agent.txt', userAgent)
    else:
        raise ScanariumError('SE_UNKNOWN_FEEDBACK_TARGET',
                             'Unknown feedback target "{feedback_target}"',
                             {'feedback_target': target})
    return True
示例#7
0
def assert_directory(dir):
    if not os.path.isdir(dir):
        raise ScanariumError('E_NO_DIR', 'Is not a directory "{file_name}"',
                             {'file_name': dir})
示例#8
0
def filter_svg_tree(scanarium,
                    tree,
                    command,
                    parameter,
                    variant,
                    localizer,
                    command_label,
                    parameter_label,
                    decoration_version,
                    href_adjustment=None):
    (localized_command, localized_parameter, localized_variant,
     localized_parameter_with_variant) = localize_command_parameter_variant(
         localizer, command, parameter, variant)

    localized_command_label = localizer.localize_parameter(
        'command_label', command_label)
    localized_parameter_label = localizer.localize_parameter(
        'parameter_label', parameter_label)

    template_parameters = {
        'actor_name': localized_parameter,
        'command_label': localized_command_label,
        'command_name': localized_command,
        'command_name_raw': command,
        'parameter_label': localized_parameter_label,
        'parameter_name': localized_parameter,
        'parameter_with_variant_name': localized_parameter_with_variant,
        'parameter_name_raw': parameter,
        'scene_name': localized_command,
        'variant_name': localized_variant,
    }

    def filter_text(text):
        if text is not None:
            text = localizer.localize(text, template_parameters)
        return text

    for element in tree.iter():
        if element.tag == '{http://www.w3.org/2000/svg}g':
            if element.get('{http://www.inkscape.org/namespaces/inkscape}'
                           'groupmode') == 'layer':
                layer_name = extract_layer_name(element)
                style_enforcings = SVG_VARIANT_SETTINGS\
                    .get(variant, {})\
                    .get('layer-settings', {})\
                    .get(layer_name, {})

        element.text = filter_text(element.text)
        element.tail = filter_text(element.tail)
        for key in element.keys():
            value = filter_text(element.get(key))
            if key == 'style' and value is not None:
                style = {}
                for setting in value.split(';'):
                    setting = setting.strip()
                    if setting:
                        k, v = setting.split(':', 1)
                        style[k.strip()] = v
                for k, v in style_enforcings.items():
                    style[k] = str(v)
                value = ';'.join(':'.join(i) for i in style.items())
            if key == 'transform' and value is not None:
                if value.split('(', 1)[0] not in ['translate', 'rotate']:
                    raise ScanariumError('E_SVG_TRANSFORM_SCALE',
                                         'SVG uses unknown transformation')
            if key == '{http://www.w3.org/1999/xlink}href':
                if value and not value.startswith('/') and '://' not in value \
                        and href_adjustment:
                    value = href_adjustment + '/' + value
            element.set(key, value)

    for qr_element in list(tree.iter("{http://www.w3.org/2000/svg}rect")):
        qr_pixel = qr_element.attrib.get('qr-pixel', None)
        if qr_pixel is not None:
            if qr_pixel == command_label:
                qr_data = f'{command}:{parameter}:d_{decoration_version}'
                expand_qr_pixel_to_qr_code(scanarium, qr_element, qr_data)
            else:
                # We want to remove this qr-pixel, as it does not match the
                # needed type. But as it might be linked to other elements, we
                # instead make it invisible to avoid messing with the layout.
                #
                # As setting `visibility` does not seem to do the trick (at
                # least in Inkscape 0.92.3), we instead set opacity. This works
                # reliably in Inkscape.
                qr_element.set('style', 'opacity:0')
示例#9
0
def generate_pdf(scanarium, dir, file, force, metadata={}):
    dpi = 150
    quality = 75
    svg_source = os.path.join(dir, file)
    pdf_name = None

    metadata['dpi'] = dpi

    formats = ['pdf']
    for format in ['png', 'jpg']:
        if scanarium.get_config('cgi:regenerate-static-content',
                                f'generate_{format}',
                                kind='boolean'):
            formats.append(format)

    for format in formats:
        target = os.path.join(dir, file.rsplit('.', 1)[0] + '.' + format)
        target_tmp = target + '.tmp.' + format  # Appending format to make sure
        # `convert` and colleagues can figure out the expected file format
        if format in ['pdf', 'png']:
            source = svg_source
            if scanarium.file_needs_update(target, [source], force):
                inkscape_args = [
                    '--export-area-page',
                    f'--export-dpi={dpi}',
                    '--export-%s=%s' % (format, target_tmp),
                ]
                if format == 'png':
                    inkscape_args.append('--export-background=white')

                inkscape_args.append(source)

                run_inkscape(scanarium, inkscape_args)
            if format == 'pdf':
                pdf_name = target
        else:
            source = os.path.join(dir, file.rsplit('.', 1)[0] + '.png')
            if not scanarium.get_config('cgi:regenerate-static-content',
                                        'generate_png',
                                        kind='boolean'):
                raise ScanariumError(
                    'SE_REGENERATE_NO_SOURCE_FOR_TARGET', 'You need to enable '
                    '`cgi:regenerate-static-content.generate_png` to generate '
                    'the target file {target_file}.', {
                        'source_file': source,
                        'target_file': target
                    })
            if scanarium.file_needs_update(target, [source], force):
                command = [
                    scanarium.get_config('programs', 'convert'), source,
                    '-units', 'pixelsperinch', '-background', 'white',
                    '-flatten', '-density',
                    str(dpi), '-quality',
                    str(quality), target_tmp
                ]
                scanarium.run(command)
        if scanarium.file_needs_update(target, [source], force):
            if scanarium.get_config('cgi:regenerate-static-content',
                                    'embed_metadata',
                                    kind='boolean'):
                embed_metadata(scanarium, target_tmp, metadata)
            shutil.move(target_tmp, target)
    return pdf_name