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)))
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
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))
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]
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')
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')
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)
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))