def _do_actions(self, context, actions): # Get API component. api = self.env[ScreenshotsApi] for action in actions: if action == 'get-file': context.req.perm.assert_permission('SCREENSHOTS_VIEW') # Get request arguments. screenshot_id = int(context.req.args.get('id') or 0) format = context.req.args.get('format') or self.default_format width = int(context.req.args.get('width') or 0) height = int(context.req.args.get('height') or 0) # Check if requested format is allowed. if not format in self.formats: raise TracError(_("Requested screenshot format that is not " "allowed."), _("Requested format not allowed.")) # Get screenshot. screenshot = api.get_screenshot(context, screenshot_id) # Check if requested screenshot exists. if not screenshot: if context.req.perm.has_permission('SCREENSHOTS_ADD'): context.req.redirect(context.req.href.screenshots( action = 'add')) else: raise TracError(_("Screenshot not found.")) # Set missing dimensions. width = width or screenshot['width'] height = height or screenshot['height'] if format == 'html': # Format screenshot for presentation. screenshot['author'] = format_to_oneliner(self.env, context, screenshot['author']) screenshot['name'] = format_to_oneliner(self.env, context, screenshot['name']) screenshot['description'] = format_to_oneliner(self.env, context, screenshot['description']) screenshot['time'] = pretty_timedelta(to_datetime( screenshot['time'], utc)) # For HTML preview format return template. context.req.data['screenshot'] = screenshot return ('screenshot', None) else: # Prepare screenshot filename. name, ext = os.path.splitext(screenshot['file']) format = (format == 'raw') and ext or '.' + format path = os.path.normpath(os.path.join(self.path, to_unicode( screenshot['id']))) filename = os.path.normpath(os.path.join(path, '%s-%sx%s%s' % (name, width, height, format))) orig_name = os.path.normpath(os.path.join(path, '%s-%sx%s%s' % (name, screenshot['width'], screenshot['height'], ext))) base_name = os.path.normpath(os.path.basename(filename)) self.log.debug('filename: %s' % (filename,)) # Create requested file from original if not exists. if not os.path.isfile(filename.encode('utf-8')): self._create_image(orig_name, path, name, format, width, height) # Guess mime type. file = open(filename.encode('utf-8'), "r") file_data = file.read(1000) file.close() mimeview = Mimeview(self.env) mime_type = mimeview.get_mimetype(filename, file_data) if not mime_type: mime_type = 'application/octet-stream' if 'charset=' not in mime_type: charset = mimeview.get_charset(file_data, mime_type) mime_type = mime_type + '; charset=' + charset # Send file to request. context.req.send_header('Content-Disposition', 'attachment;filename="%s"' % (base_name)) context.req.send_header('Content-Description', screenshot['description']) context.req.send_file(filename.encode('utf-8'), mime_type) elif action == 'add': context.req.perm.assert_permission('SCREENSHOTS_ADD') # Get request arguments. index = int(context.req.args.get('index') or 0) # Fill data dictionary. context.req.data['index'] = index context.req.data['versions'] = api.get_versions(context) context.req.data['components'] = api.get_components(context) # Return template with add screenshot form. return ('screenshot-add', None) elif action == 'post-add': context.req.perm.assert_permission('SCREENSHOTS_ADD') # Get image file from request. file, filename = self._get_file_from_req(context.req) name, ext = os.path.splitext(filename) ext = ext.lower() filename = name + ext # Is uploaded file archive or single image? if ext == '.zip': # Get global timestamp for all files in archive. timestamp = to_timestamp(datetime.now(utc)) # List files in archive. zip_file = ZipFile(file) for filename in zip_file.namelist(): # Test file extensions for supported type. name, ext = os.path.splitext(filename) tmp_ext = ext.lower()[1:] if tmp_ext in self.ext and tmp_ext != 'zip': # Decompress image file data = zip_file.read(filename) file = StringIO(data) filename = to_unicode(os.path.basename(filename)) # Screenshots must be identified by timestamp. timestamp += 1 # Create image object. image = Image.open(file) # Construct screenshot dictionary from form values. screenshot = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description'), 'time' : timestamp, 'author' : context.req.authname, 'tags' : context.req.args.get('tags'), 'file' : filename, 'width' : image.size[0], 'height' : image.size[1], 'priority' : int(context.req.args.get('priority') or '0')} self.log.debug('screenshot: %s' % (screenshot,)) # Save screenshot file and add DB entry. self._add_screenshot(context, api, screenshot, file) zip_file.close() else: # Create image object. image = Image.open(file) # Construct screenshot dictionary from form values. screenshot = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description'), 'time' : to_timestamp(datetime.now(utc)), 'author' : context.req.authname, 'tags' : context.req.args.get('tags'), 'file' : filename, 'width' : image.size[0], 'height' : image.size[1], 'priority' : int(context.req.args.get('priority') or '0')} self.log.debug('screenshot: %s' % (screenshot,)) # Add single image. self._add_screenshot(context, api, screenshot, file) # Close input file. file.close() # Clear ID to prevent display of edit and delete button. context.req.args['id'] = None elif action == 'edit': context.req.perm.assert_permission('SCREENSHOTS_EDIT') # Get request arguments. screenshot_id = context.req.args.get('id') # Prepare data dictionary. context.req.data['screenshot'] = api.get_screenshot(context, screenshot_id) elif action == 'post-edit': context.req.perm.assert_permission('SCREENSHOTS_EDIT') # Get screenshot arguments. screenshot_id = int(context.req.args.get('id') or 0) # Get old screenshot old_screenshot = api.get_screenshot(context, screenshot_id) # Check if requested screenshot exits. if not old_screenshot: raise TracError(_("Edited screenshot not found."), _("Screenshot not found.")) # Get image file from request. image = context.req.args['image'] if hasattr(image, 'filename') and image.filename: in_file, filename = self._get_file_from_req(context.req) name, ext = os.path.splitext(filename) filename = name + ext.lower() else: filename = None # Construct screenshot dictionary from form values. screenshot = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description'), 'author' : context.req.authname, 'tags' : context.req.args.get('tags'), 'components' : context.req.args.get('components') or [], 'versions' : context.req.args.get('versions') or [], 'priority' : int(context.req.args.get('priority') or '0')} # Update dimensions and filename if image file is updated. if filename: image = Image.open(in_file) screenshot['file'] = filename screenshot['width'] = image.size[0] screenshot['height'] = image.size[1] # Convert components and versions to list if only one item is # selected. if not isinstance(screenshot['components'], list): screenshot['components'] = [screenshot['components']] if not isinstance(screenshot['versions'], list): screenshot['versions'] = [screenshot['versions']] self.log.debug('screenshot: %s' % (screenshot)) # Edit screenshot. api.edit_screenshot(context, screenshot_id, screenshot) # Prepare file paths. if filename: name, ext = os.path.splitext(screenshot['file']) path = os.path.normpath(os.path.join(self.path, to_unicode( screenshot_id))) filepath = os.path.normpath(os.path.join(path, '%s-%ix%i%s' % (name, screenshot['width'], screenshot['height'], ext))) self.log.debug('path: %s' % (path,)) self.log.debug('filepath: %s' % (filepath,)) # Delete present images. try: for file in os.listdir(path): file = os.path.normpath(os.path.join(path, to_unicode(file))) os.remove(file.encode('utf-8')) except Exception, error: raise TracError(_("Error deleting screenshot. Original " "error message was: %s""") % (to_unicode(error),)) # Store uploaded image. try: out_file = open(filepath.encode('utf-8'), 'wb+') in_file.seek(0) shutil.copyfileobj(in_file, out_file) out_file.close() except Exception, error: try: os.remove(filepath.encode('utf-8')) except: pass raise TracError(_("Error storing file. Is directory " "specified in path config option in [screenshots] " "section of trac.ini existing? Original error " "message was: %s") % (to_unicode(error),)) # Notify change listeners. for listener in self.change_listeners: listener.screenshot_changed(context.req, screenshot, old_screenshot) # Clear ID to prevent display of edit and delete button. context.req.args['id'] = None