def _get_file(value) -> _file.model.AbstractFile:
    if isinstance(value, _file.model.AbstractFile):
        return value

    elif isinstance(value, str):
        return _file.get(value)

    # To directly support HTTP API requests
    elif isinstance(value, dict):
        if 'uid' not in value:
            raise ValueError("Dictionary must contain 'uid' key")

        return _file.get(value['uid'])

    # Backward compatibility
    elif isinstance(value, _DBRef):
        if value.collection == 'images':
            return _file.get('file_image:' + str(value.id))
        else:
            raise ValueError(
                'Cannot determine collection of DB reference: {}'.format(
                    value))

    else:
        raise TypeError(
            'File object, string UID or dict expected, got {}'.format(
                type(value)))
Beispiel #2
0
 def _on_form_submit(self, request: http.Request):
     """Hook
     """
     # Delete files which are has been removed from the widget on the browser's side,
     # ONLY if the form is not in validation mode
     to_delete = request.inp.get(self._uid + '_to_delete')
     if to_delete:
         if isinstance(to_delete, str):
             to_delete = [to_delete]
         for uid in to_delete:
             try:
                 file.get(uid).delete()
             except file.error.FileNotFound:
                 pass
    def exec(self):
        if auth.get_current_user().is_anonymous:
            raise self.forbidden()

        if not self.request.files:
            raise RuntimeError('No files received')

        r = []
        for field_name, f in self.request.files.items():
            tmp_file_path = util.mk_tmp_file()[1]
            f.save(tmp_file_path)

            f = file.create(tmp_file_path, f.filename, 'Uploaded via HTTP API')
            unlink(tmp_file_path)

            r.append({
                'uid': str(f.uid),
            })

        # Request was from CKEditor
        if self.arg('CKEditor') and self.arg('CKEditorFuncNum'):
            script = 'window.parent.CKEDITOR.tools.callFunction("{}", "{}", "");' \
                .format(self.arg('CKEditorFuncNum'), file.get(r[0]['uid']).get_url())

            # CKEditor requires such response format
            r = http.Response(
                '<script type="text/javascript">{}</script>'.format(script),
                mimetype='text/html')

        return r
Beispiel #4
0
 def logo_url(width: int = 0, height: int = 0, enlarge: bool = False):
     s = reg.get('theme.logo')
     try:
         return file.get(s).get_url(width=width, height=height, enlarge=enlarge) if s else \
             assetman.url('$theme@img/appicon.png')
     except file.error.FileNotFound:
         return assetman.url('$theme@img/appicon.png')
    def exec(self) -> dict:
        if auth.get_current_user().is_anonymous:
            raise self.forbidden()

        try:
            return file.get(self.arg('uid')).as_jsonable(**self.args)

        except file.error.FileNotFound as e:
            raise self.not_found(str(e))
Beispiel #6
0
    def get_files(self) -> List[file.model.AbstractFile]:
        """Get value of the widget as a list of file objects
        """
        value = self.get_val()

        if not isinstance(value, (list, tuple)):
            value = [value] if value else []

        return [file.get(fid) for fid in value]
Beispiel #7
0
def test_paths_exists():
    """ 
    Test for path existence using http codes and computed 404
    Spawn workers and turn off output for now, it would be irrelevant at this point. 
    """
    manager = ThreadManager()

    # Fill work queue with fetch list
    for path in database.paths:
        dbutils.add_path_to_fetch_queue(path)

    # Consider some file target as potential path
    for file in database.files:
        if not file.get('no_suffix'):
            file_as_path = file.copy()
            file_as_path['url'] = '/' + file_as_path['url']
            dbutils.add_path_to_fetch_queue(file_as_path)

    done_paths = []
    recursion_depth = 0

    textutils.output_debug('Cached: ' + str(database.path_cache))
    while database.fetch_queue.qsize() > 0:
        textutils.output_info('Probing ' + str(database.fetch_queue.qsize()) +
                              ' paths')

        # Wait for initial valid path lookup
        workers = manager.spawn_workers(conf.thread_count,
                                        TestPathExistsWorker)
        manager.wait_for_idle(workers, database.fetch_queue)

        recursion_depth += 1

        if not conf.recursive:
            break

        if recursion_depth >= conf.recursive_depth_limit:
            break

        for validpath in database.valid_paths:

            if validpath['url'] == '/' or validpath['url'] in done_paths:
                continue

            done_paths.append(validpath['url'])

            for path in database.paths:
                if path['url'] in ('/', ''):
                    continue
                path = path.copy()
                path['url'] = validpath['url'] + path['url']
                dbutils.add_path_to_fetch_queue(path)

    textutils.output_info('Found ' + str(len(database.valid_paths)) +
                          ' valid paths')
Beispiel #8
0
def test_paths_exists():
    """ 
    Test for path existence using http codes and computed 404
    Spawn workers and turn off output for now, it would be irrelevant at this point. 
    """
    manager = ThreadManager()
    
    # Fill work queue with fetch list
    for path in database.paths:
        dbutils.add_path_to_fetch_queue(path)

    # Consider some file target as potential path
    for file in database.files:
        if not file.get('no_suffix'):
            file_as_path = file.copy()
            file_as_path['url'] = '/' + file_as_path['url']
            dbutils.add_path_to_fetch_queue(file_as_path)

    done_paths = []
    recursion_depth = 0

    textutils.output_debug('Cached: ' + str(database.path_cache))
    while database.fetch_queue.qsize() > 0:
        textutils.output_info('Probing ' + str(database.fetch_queue.qsize()) + ' paths')

        # Wait for initial valid path lookup
        workers = manager.spawn_workers(conf.thread_count, TestPathExistsWorker)
        manager.wait_for_idle(workers, database.fetch_queue)

        recursion_depth += 1
        
        if not conf.recursive:
            break
        
        if recursion_depth >= conf.recursive_depth_limit:
            break    
        
        for validpath in database.valid_paths:
            
            if validpath['url'] == '/' or validpath['url'] in done_paths:
                continue
            
            done_paths.append(validpath['url'])
            
            for path in database.paths:
                if path['url'] in ('/', ''):
                    continue
                path = path.copy()
                path['url'] = validpath['url'] + path['url']
                dbutils.add_path_to_fetch_queue(path)

    textutils.output_info('Found ' + str(len(database.valid_paths)) + ' valid paths')
Beispiel #9
0
    def set_val(self, value: Union[list, tuple]):
        """Set value of the widget
        """
        if value is None:
            return

        # Always process value as multiple files
        if not isinstance(value, (list, tuple)):
            value = [value]

        # Filter out empty values, sanitize valid values
        clean_val = []
        for val in value:
            # Empty value
            if not val:
                continue
            # Files object convert to string UIDs
            elif isinstance(val, file.model.AbstractFile):
                clean_val.append(val.uid)
            # Strings remain as is
            elif isinstance(val, str):
                try:
                    file.get(val)  # Check if the file exists
                    clean_val.append(val)
                except file.error.FileNotFound as e:
                    if not self._skip_missing:
                        raise e
            else:
                raise TypeError(
                    "String or file object expected, got '{}'".format(
                        type(val)))

        # Sanitize storage type
        if self._max_files == 1:
            clean_val = clean_val[0] if clean_val else None

        super().set_val(clean_val)
Beispiel #10
0
def on_router_dispatch():
    """pytsite.router.dispatch
    """
    if not assetman.is_package_registered(_api.get().package_name):
        return

    # Set current theme package
    metatag.t_set('pytsite-theme', _api.get().package_name)

    # Set favicon URL
    favicon_fid = reg.get('theme.favicon')
    if favicon_fid:
        try:
            f = file.get(favicon_fid)
            metatag.t_set('link', rel='icon', type=f.mime, href=f.get_url(width=50, height=50))
        except file.error.FileNotFound:
            pass
    else:
        metatag.t_set('link', rel='icon', type='image/png', href=assetman.url('$theme@img/favicon.png'))
    def exec(self):

        requested_width = int(self.arg('width'))
        requested_height = int(self.arg('height'))
        p1 = self.arg('p1')
        p2 = self.arg('p2')
        filename = self.arg('filename')
        uid = 'file_image:' + _path.splitext(filename)[0]

        try:
            img_file = _file.get(uid)  # type: _model.ImageFile
        except _file.error.FileNotFound as e:
            raise self.not_found(str(e))

        # Align side lengths and redirect
        aligned_width = _api.align_image_side(
            requested_width, _api.get_image_resize_limit_width())
        aligned_height = _api.align_image_side(
            requested_height, _api.get_image_resize_limit_height())
        if aligned_width != requested_width or aligned_height != requested_height:
            redirect = _router.rule_url(
                'file_storage_odm@image', {
                    'width': aligned_width,
                    'height': aligned_height,
                    'p1': p1,
                    'p2': p2,
                    'filename': filename,
                })
            return self.redirect(redirect, 301)

        # Original size
        orig_width = img_file.width
        orig_height = img_file.height
        orig_ratio = orig_width / orig_height

        need_resize = True

        # Calculate new size
        if not requested_width and not requested_height:
            # No resize needed, return original image
            resize_width = orig_width
            resize_height = orig_height
            need_resize = False
        elif requested_width and not requested_height:
            # Resize by width, preserve aspect ration
            resize_width = requested_width
            resize_height = _floor(requested_width / orig_ratio)
        elif requested_height and not requested_width:
            # Resize by height, preserve aspect ration
            resize_width = _floor(requested_height * orig_ratio)
            resize_height = requested_height
        else:
            # Exact resizing
            resize_width = requested_width
            resize_height = requested_height

        # Checking source file
        storage_path = img_file.get_field('storage_path')
        if not _path.exists(storage_path):
            return self.redirect('http://placehold.it/{}x{}'.format(
                requested_width, requested_height))

        # Calculating target file location
        static_path = _path.join(_reg.get('paths.static'), 'image', 'resize',
                                 str(requested_width), str(requested_height),
                                 p1, p2, filename)

        # Create target directory
        target_dir = _path.dirname(static_path)
        if not _path.exists(target_dir):
            _makedirs(target_dir, 0o755, True)

        if not _path.exists(static_path):
            # Open source image
            img = _Image.open(storage_path)  # type: _Image

            # Resize
            if need_resize:
                # Crop
                crop_ratio = resize_width / resize_height
                crop_width = orig_width
                crop_height = _floor(crop_width / crop_ratio)
                crop_top = _floor(orig_height / 2) - _floor(crop_height / 2)
                crop_left = 0
                if crop_height > orig_height:
                    crop_height = orig_height
                    crop_width = _floor(crop_height * crop_ratio)
                    crop_top = 0
                    crop_left = _floor(orig_width / 2) - _floor(crop_width / 2)
                crop_right = crop_left + crop_width
                crop_bottom = crop_top + crop_height

                cropped = img.crop(
                    (crop_left, crop_top, crop_right, crop_bottom))
                img.close()

                # Resize
                img = cropped.resize((resize_width, resize_height),
                                     _Image.BILINEAR)

            img.save(static_path)
            img.close()

        return self.redirect(
            img_file.get_url(width=requested_width, height=requested_height))