def _render_diff(self, req, filename, repos, diff, diff_options): """Raw Unified Diff version""" req.send_response(200) req.send_header('Content-Type', 'text/plain;charset=utf-8') req.send_header('Content-Disposition', 'inline;' 'filename=%s.diff' % filename) req.end_headers() mimeview = Mimeview(self.env) for old_node, new_node, kind, change in repos.get_changes(**diff): # TODO: Property changes # Content changes if kind == Node.DIRECTORY: continue new_content = old_content = '' new_node_info = old_node_info = ('','') mimeview = Mimeview(self.env) if old_node: old_content = old_node.get_content().read() if is_binary(old_content): continue old_node_info = (old_node.path, old_node.rev) old_content = mimeview.to_unicode(old_content, old_node.content_type) if new_node: new_content = new_node.get_content().read() if is_binary(new_content): continue new_node_info = (new_node.path, new_node.rev) new_path = new_node.path new_content = mimeview.to_unicode(new_content, new_node.content_type) else: old_node_path = repos.normalize_path(old_node.path) diff_old_path = repos.normalize_path(diff.old_path) new_path = posixpath.join(diff.new_path, old_node_path[len(diff_old_path)+1:]) if old_content != new_content: context = 3 options = diff_options[1] for option in options: if option.startswith('-U'): context = int(option[2:]) break if not old_node_info[0]: old_node_info = new_node_info # support for 'A'dd changes req.write('Index: ' + new_path + CRLF) req.write('=' * 67 + CRLF) req.write('--- %s (revision %s)' % old_node_info + CRLF) req.write('+++ %s (revision %s)' % new_node_info + CRLF) for line in unified_diff(old_content.splitlines(), new_content.splitlines(), context, ignore_blank_lines='-B' in options, ignore_case='-i' in options, ignore_space_changes='-b' in options): req.write(line + CRLF)
def process_request(self, req): """Process the request. For ClearSilver, return a (template_name, content_type) tuple, where `template` is the ClearSilver template to use (either a `neo_cs.CS` object, or the file name of the template), and `content_type` is the MIME type of the content. For Genshi, return a (template_name, data, content_type) tuple, where `data` is a dictionary of substitutions for the template. For both templating systems, "text/html" is assumed if `content_type` is `None`. Note that if template processing should not occur, this method can simply send the response itself and not return anything. """ # handle image setting if req.method == 'POST': self.set_default_image(req) req.redirect(req.get_header('referer') or req.href(req.path_info)) # GET default image ticket_id, size = self.ticket_id_and_size(req.path_info) image = DefaultTicketImage(self.env).default_image(ticket_id, size) assert image is not None # TODO better images = ImageTrac(self.env).images(ticket_id) attachment = Attachment(self.env, 'ticket', ticket_id, images[image][size]) mimeview = Mimeview(self.env) mimetype = mimeview.get_mimetype(attachment.filename) req.send(attachment.open().read(), mimetype)
def validate_ticket(self, req, ticket): """Validate a ticket after it's been populated from user input. Must return a list of `(field, message)` tuples, one for each problem detected. `field` can be `None` to indicate an overall problem with the ticket. Therefore, a return value of `[]` means everything is OK.""" image = req.args.get('ticket_image') if hasattr(image, 'fp'): mimeview = Mimeview(self.env) mimetype = mimeview.get_mimetype(image.filename) if mimetype is None: return [('ticket_image', 'Uploaded file is not an image')] if mimetype.split('/', 1)[0] != 'image': return [('ticket_image', 'Uploaded file is not an image, instead it is %s' % mimetype)] try: Image.open(image.file) except IOError, e: return [('ticket_image', str(e))] # store the image temporarily for new tickets if ticket.exists: self.attach(ticket, image) else: if not hasattr(self, 'image'): self.image = {} self.image[ticket['summary']] = req.args['ticket_image']
def validate_ticket(self, req, ticket): """Validate a ticket after it's been populated from user input. Must return a list of `(field, message)` tuples, one for each problem detected. `field` can be `None` to indicate an overall problem with the ticket. Therefore, a return value of `[]` means everything is OK.""" image = req.args.get('ticket_image') if hasattr(image, 'fp'): mimeview = Mimeview(self.env) mimetype = mimeview.get_mimetype(image.filename) if mimetype is None: return[('ticket_image', 'Uploaded file is not an image')] if mimetype.split('/',1)[0] != 'image': return [('ticket_image', 'Uploaded file is not an image, instead it is %s' % mimetype)] try: Image.open(image.file) except IOError, e: return[('ticket_image', str(e))] # store the image temporarily for new tickets if ticket.exists: self.attach(ticket, image) else: if not hasattr(self, 'image'): self.image = {} self.image[ticket['summary']] = req.args['ticket_image']
def filter_stream(self, req, method, filename, stream, data): action = req.args.get('action', '') if filename == 'browser.html' and action == 'edit': req.perm.require('REPOSITORY_MODIFY') # NB TracBrowserOps already inserts javascript and css we need # So only add css/javascript needed solely by the editor if data['file'] and data['file']['preview']['rendered']: max_edit_size = self.max_edit_size data['max_edit_size'] = max_edit_size # Discard rendered table, replace with textarea of file contents # This means reading the file from the repository again # N.B. If a file is rendered as something other than a table # e.g. due to PreCodeBrowserPlugin this code won't trigger # Retrieve the same node that BrowserModule.process_request() # used to render the preview. # At this point reponame has been removed from data['path'] # and repos has already been determined repos = data['repos'] path = data['path'] rev = data['rev'] node = repos.get_node(path, rev) # If node is too large then don't allow editing, abort if max_edit_size > 0 and node.content_length > max_edit_size: return stream # Open the node and read it node_file = node.get_content() node_data = node_file.read() # Discover the mime type and character encoding of the node # Try in order # - svn:mime-type property # - detect from file name and content (BOM) # - use configured default for Trac mime_view = Mimeview(self.env) mime_type = node.content_type \ or mime_view.get_mimetype(node.name, node_data) \ or 'text/plain' encoding = mime_view.get_charset(node_data, mime_type) # Populate template data content = mime_view.to_unicode(node_data, mime_type, encoding) data['file_content'] = content data['file_encoding'] = encoding # Replace the already rendered preview with a form and textarea bsops_stream = Chrome(self.env).render_template( req, 'file_edit.html', data, fragment=True) transf = Transformer('//div[@id="preview"]' '/table[@class="code"]') stream |= transf.replace( bsops_stream.select('//div[@id="bsop_edit"]')) return stream
def filter_stream(self, req, method, filename, stream, data): action = req.args.get('action', '') if filename == 'browser.html' and action == 'edit': req.perm.require('REPOSITORY_MODIFY') # NB TracBrowserOps already inserts javascript and css we need # So only add css/javascript needed solely by the editor if data['file'] and data['file']['preview']['rendered']: max_edit_size = self.max_edit_size data['max_edit_size'] = max_edit_size # Discard rendered table, replace with textarea of file contents # This means reading the file from the repository again # N.B. If a file is rendered as something other than a table # e.g. due to PreCodeBrowserPlugin this code won't trigger # Retrieve the same node that BrowserModule.process_request() # used to render the preview. # At this point reponame has been removed from data['path'] # and repos has already been determined repos = data['repos'] path = data['path'] rev = data['rev'] node = repos.get_node(path, rev) # If node is too large then don't allow editing, abort if max_edit_size > 0 and node.content_length > max_edit_size: return stream # Open the node and read it node_file = node.get_content() node_data = node_file.read() # Discover the mime type and character encoding of the node # Try in order # - svn:mime-type property # - detect from file name and content (BOM) # - use configured default for Trac mime_view = Mimeview(self.env) mime_type = node.content_type \ or mime_view.get_mimetype(node.name, node_data) \ or 'text/plain' encoding = mime_view.get_charset(node_data, mime_type) # Populate template data content = mime_view.to_unicode(node_data, mime_type, encoding) data['file_content'] = content data['file_encoding'] = encoding # Replace the already rendered preview with a form and textarea bsops_stream = Chrome(self.env).render_template(req, 'file_edit.html', data, fragment=True) transf = Transformer('//div[@id="preview"]' '/table[@class="code"]') stream |= transf.replace( bsops_stream.select('//div[@id="bsop_edit"]')) return stream
def add_backlog_conversion_links(env, req, backlog, backlog_url): # TODO: Move tests to new backlog mime = Mimeview(env) for conversion in mime.get_supported_conversions(BACKLOG_CONVERSION_KEY): format = conversion[0] title = conversion[1] mimetype = conversion[4] backlog_href = req.href(backlog_url, backlog.name, backlog.scope, format=format) add_link(req, 'alternate', backlog_href, title, mimetype, format)
def image(self, ticket): """ return the first image attachment or None if there aren't any """ attachments = list(Attachment.select(self.env, 'ticket', ticket.id)) mimeview = Mimeview(self.env) for attachment in attachments: mimetype = mimeview.get_mimetype(attachment.filename) if not mimetype or mimetype.split('/',1)[0] != 'image': continue return attachment.filename
def source( req, argument_text, env, aswiki =False): from trac.versioncontrol.web_ui.util import get_existing_node, get_path_rev_line ## XXX above .util is shaded by trac.util? path,rev,line = get_path_rev_line( argument_text) from trac.mimeview import Mimeview, get_mimetype, content_to_unicode repos = env.get_repository() # req.authname) node = get_existing_node( env, repos, path, rev) content = node.get_content().read() if aswiki: mimetype = 'text/x-trac-wiki' r = wiki_to_html( content_to_unicode( env, content, mimetype), env=env, req=req) else: mimetype = get_mimetype( os.path.basename( path) ) or 'text/plain ' mimeview = Mimeview( env) #charset = mimeview.get_charset( content, mimetype) #node.content_type? #content = util.to_utf8( content, charset ) r = mimeview.render( req, mimetype, content) return r, None
def image_category(self, attachment): reverse_sizes = dict([(value, key) for key, value in self.sizes().items()]) mimeview = Mimeview(self.env) mimetype = mimeview.get_mimetype(attachment.filename) if mimetype and mimetype.split('/',1)[0] != 'image': return None filename = attachment.filename try: size = Image.open(attachment.path).size except IOError: return None for _size in reverse_sizes: parts = filename.rsplit('.', 2) if len(parts) == 3: dimension = '%sx%s' % (_size[0] or '', _size[1] or '') if parts[-2] == dimension: filename = '%s.%s' % (parts[0], parts[-1]) return (filename, reverse_sizes[_size]) return (filename, 'original')
def image_category(self, attachment): reverse_sizes = dict([(value, key) for key, value in self.sizes().items()]) mimeview = Mimeview(self.env) mimetype = mimeview.get_mimetype(attachment.filename) if mimetype and mimetype.split('/', 1)[0] != 'image': return None filename = attachment.filename try: size = Image.open(attachment.path).size except IOError: return None for _size in reverse_sizes: parts = filename.rsplit('.', 2) if len(parts) == 3: dimension = '%sx%s' % (_size[0] or '', _size[1] or '') if parts[-2] == dimension: filename = '%s.%s' % (parts[0], parts[-1]) return (filename, reverse_sizes[_size]) return (filename, 'original')
def _content_changes(old_node, new_node): """Returns the list of differences. The list is empty when no differences between comparable files are detected, but the return value is None for non-comparable files. """ old_content = old_node.get_content().read() if is_binary(old_content): return None new_content = new_node.get_content().read() if is_binary(new_content): return None mview = Mimeview(self.env) old_content = mview.to_unicode(old_content, old_node.content_type) new_content = mview.to_unicode(new_content, new_node.content_type) if old_content != new_content: context = 3 options = diff_options[1] for option in options: if option.startswith('-U'): context = int(option[2:]) break if context < 0: context = None tabwidth = self.config['diff'].getint('tab_width') or \ self.config['mimeviewer'].getint('tab_width', 8) return hdf_diff(old_content.splitlines(), new_content.splitlines(), context, tabwidth, ignore_blank_lines='-B' in options, ignore_case='-i' in options, ignore_space_changes='-b' in options) else: return []
def _content_changes(old_node, new_node): """Returns the list of differences. The list is empty when no differences between comparable files are detected, but the return value is None for non-comparable files. """ mview = Mimeview(self.env) if mview.is_binary(old_node.content_type, old_node.path): return None if mview.is_binary(new_node.content_type, new_node.path): return None old_content = old_node.get_content().read() if mview.is_binary(content=old_content): return None new_content = new_node.get_content().read() if mview.is_binary(content=new_content): return None old_content = mview.to_unicode(old_content, old_node.content_type) new_content = mview.to_unicode(new_content, new_node.content_type) if old_content != new_content: context = options.get('contextlines', 3) if context < 0: context = None tabwidth = self.config['diff'].getint('tab_width') or \ self.config['mimeviewer'].getint('tab_width', 8) ignore_blank_lines = options.get('ignoreblanklines') ignore_case = options.get('ignorecase') ignore_space = options.get('ignorewhitespace') return diff_blocks(old_content.splitlines(), new_content.splitlines(), context, tabwidth, ignore_blank_lines=ignore_blank_lines, ignore_case=ignore_case, ignore_space_changes=ignore_space) else: return []
def _render_file(self, req, repos, node, rev=None): req.perm.assert_permission('FILE_VIEW') mimeview = Mimeview(self.env) # MIME type detection content = node.get_content() chunk = content.read(CHUNK_SIZE) mime_type = node.content_type if not mime_type or mime_type == 'application/octet-stream': mime_type = mimeview.get_mimetype(node.name, chunk) or \ mime_type or 'text/plain' # Eventually send the file directly format = req.args.get('format') if format in ['raw', 'txt']: req.send_response(200) req.send_header('Content-Type', format == 'txt' and 'text/plain' or mime_type) req.send_header('Content-Length', node.content_length) req.send_header('Last-Modified', http_date(node.last_modified)) if not self.render_unsafe_content: # Force browser to download files instead of rendering # them, since they might contain malicious code enabling # XSS attacks req.send_header('Content-Disposition', 'attachment') req.end_headers() while 1: if not chunk: raise RequestDone req.write(chunk) chunk = content.read(CHUNK_SIZE) else: # The changeset corresponding to the last change on `node` # is more interesting than the `rev` changeset. changeset = repos.get_changeset(node.rev) message = changeset.message or '--' if self.config['changeset'].getbool('wiki_format_messages'): message = wiki_to_html(message, self.env, req, escape_newlines=True) else: message = html.PRE(message) ZhUnit = {'second':u'秒','seconds':u'秒','minute':u'分钟','minutes':u'分钟','hour':u'小时','hours':u'小时', 'day':u'天','days':u'天','year':u'年','years':u'年','month':u'月','months':u'月'} tempTime = pretty_timedelta(changeset.date) numAndUnit = tempTime.split(' ') numAndUnit[1] = ZhUnit.get(numAndUnit[1],numAndUnit[1]) ZhAge = ' '.join(numAndUnit) req.hdf['file'] = { 'rev': node.rev, 'changeset_href': req.href.changeset(node.rev), 'date': format_datetime(changeset.date), 'age': ZhAge, 'size': pretty_size(node.content_length), 'author': changeset.author or 'anonymous', 'message': message } # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != 'text/plain': plain_href = req.href.browser(node.path, rev=rev, format='txt') add_link(req, 'alternate', plain_href, 'Plain Text', 'text/plain') # add ''Original Format'' alternate link (always) raw_href = req.href.browser(node.path, rev=rev, format='raw') add_link(req, 'alternate', raw_href, 'Original Format', mime_type) self.log.debug("Rendering preview of node %s@%s with mime-type %s" % (node.name, str(rev), mime_type)) del content # the remainder of that content is not needed req.hdf['file'] = mimeview.preview_to_hdf( req, node.get_content(), node.get_content_length(), mime_type, node.created_path, raw_href, annotations=['lineno']) add_stylesheet(req, 'common/css/code.css')
def _render_file(self, req, repos, node, rev=None): req.perm.assert_permission('FILE_VIEW') mimeview = Mimeview(self.env) # MIME type detection content = node.get_content() chunk = content.read(CHUNK_SIZE) mime_type = node.content_type if not mime_type or mime_type == 'application/octet-stream': mime_type = mimeview.get_mimetype(node.name, chunk) or \ mime_type or 'text/plain' # Eventually send the file directly format = req.args.get('format') if format in ['raw', 'txt']: req.send_response(200) req.send_header('Content-Type', format == 'txt' and 'text/plain' or mime_type) req.send_header('Content-Length', node.content_length) req.send_header('Last-Modified', http_date(node.last_modified)) req.end_headers() while 1: if not chunk: raise RequestDone req.write(chunk) chunk = content.read(CHUNK_SIZE) else: # The changeset corresponding to the last change on `node` # is more interesting than the `rev` changeset. changeset = repos.get_changeset(node.rev) message = changeset.message or '--' if self.config['changeset'].getbool('wiki_format_messages'): message = wiki_to_html(message, self.env, req, escape_newlines=True) else: message = html.PRE(message) req.hdf['file'] = { 'rev': node.rev, 'changeset_href': req.href.changeset(node.rev), 'date': format_datetime(changeset.date), 'age': pretty_timedelta(changeset.date), 'size': pretty_size(node.content_length), 'author': changeset.author or 'anonymous', 'message': message } # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != 'text/plain': plain_href = req.href.browser(node.path, rev=rev, format='txt') add_link(req, 'alternate', plain_href, 'Plain Text', 'text/plain') # add ''Original Format'' alternate link (always) raw_href = req.href.browser(node.path, rev=rev, format='raw') add_link(req, 'alternate', raw_href, u'Format original', mime_type) self.log.debug( "Rendering preview of node %s@%s with mime-type %s" % (node.name, str(rev), mime_type)) del content # the remainder of that content is not needed req.hdf['file'] = mimeview.preview_to_hdf( req, node.get_content(), node.get_content_length(), mime_type, node.created_path, raw_href, annotations=['lineno']) add_stylesheet(req, 'common/css/code.css')
def _do_actions(self, context, actions): for action in actions: if action == 'get-file': context.req.perm.require('DOWNLOADS_VIEW') # Get request arguments. download_id = context.req.args.get('id') or 0 download_file = context.req.args.get('file') # Get download. if download_id: download = self.get_download(context, download_id) else: download = self.get_download_by_file( context, download_file) # Check if requested download exists. if not download: raise TracError('File not found.') # Check resource based permission. context.req.perm.require('DOWNLOADS_VIEW', Resource('downloads', download['id'])) # Get download file path. path = os.path.normpath( os.path.join(self.path, to_unicode(download['id']), download['file'])) self.log.debug('path: %s' % (path, )) # Increase downloads count. new_download = {'count': download['count'] + 1} # Edit download. self.edit_download(context, download['id'], new_download) # Notify change listeners. for listener in self.change_listeners: listener.download_changed(context, new_download, download) # Commit DB before file send. db = self.env.get_db_cnx() db.commit() # Guess mime type. file = open(path.encode('utf-8'), "r") file_data = file.read(1000) file.close() mimeview = Mimeview(self.env) mime_type = mimeview.get_mimetype(path, 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 # Return uploaded file to request. context.req.send_header( 'Content-Disposition', 'attachment;filename="%s"' % (os.path.normpath(download['file']))) context.req.send_header('Content-Description', download['description']) context.req.send_file(path.encode('utf-8'), mime_type) elif action == 'downloads-list': context.req.perm.require('DOWNLOADS_VIEW') self.log.debug('visible_fields: %s' % (self.visible_fields, )) # Get form values. order = context.req.args.get('order') or self.download_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.download_sort_direction == 'desc' self.data['order'] = order self.data['desc'] = desc self.data['has_tags'] = self.env.is_component_enabled( 'tractags.api.TagEngine') self.data['visible_fields'] = self.visible_fields self.data['title'] = self.title self.data['description'] = self.get_description(context) self.data['downloads'] = self.get_downloads( context, order, desc) self.data['visible_fields'] = [ visible_field for visible_field in self.visible_fields ] # Component, versions, etc. are needed only for new download # add form. if context.req.perm.has_permission('DOWNLOADS_ADD'): self.data['components'] = self.get_components(context) self.data['versions'] = self.get_versions(context) self.data['architectures'] = self.get_architectures( context) self.data['platforms'] = self.get_platforms(context) self.data['types'] = self.get_types(context) elif action == 'admin-downloads-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values order = context.req.args.get('order') or self.download_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.download_sort_direction == 'desc' download_id = int(context.req.args.get('download') or 0) self.data['order'] = order self.data['desc'] = desc self.data['has_tags'] = self.env.is_component_enabled( 'tractags.api.TagEngine') self.data['download'] = self.get_download(context, download_id) self.data['downloads'] = self.get_downloads( context, order, desc) self.data['components'] = self.get_components(context) self.data['versions'] = self.get_versions(context) self.data['architectures'] = self.get_architectures(context) self.data['platforms'] = self.get_platforms(context) self.data['types'] = self.get_types(context) elif action == 'description-edit': context.req.perm.require('DOWNLOADS_ADMIN') elif action == 'description-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. description = context.req.args.get('description') # Set new description. self.edit_description(context, description) elif action == 'downloads-post-add': context.req.perm.require('DOWNLOADS_ADD') # Get form values. file, filename, file_size = self._get_file_from_req(context) download = { 'file': filename, 'description': context.req.args.get('description'), 'size': file_size, 'time': to_timestamp(datetime.now(utc)), 'count': 0, 'author': context.req.authname, 'tags': context.req.args.get('tags'), 'component': context.req.args.get('component'), 'version': context.req.args.get('version'), 'architecture': context.req.args.get('architecture'), 'platform': context.req.args.get('platform'), 'type': context.req.args.get('type') } # Upload file to DB and file storage. self._add_download(context, download, file) # Close input file. file.close() elif action == 'downloads-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. download_id = context.req.args.get('id') old_download = self.get_download(context, download_id) download = { 'description': context.req.args.get('description'), 'tags': context.req.args.get('tags'), 'component': context.req.args.get('component'), 'version': context.req.args.get('version'), 'architecture': context.req.args.get('architecture'), 'platform': context.req.args.get('platform'), 'type': context.req.args.get('type') } # Edit Download. self.edit_download(context, download_id, download) # Notify change listeners. for listener in self.change_listeners: listener.download_changed(context, download, old_download) elif action == 'downloads-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected downloads. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete download. if selection: for download_id in selection: download = self.get_download(context, download_id) self.log.debug('download: %s' % (download, )) self._delete_download(context, download) elif action == 'admin-architectures-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values order = context.req.args.get('order') or self.architecture_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.architecture_sort_direction == 'desc' architecture_id = int( context.req.args.get('architecture') or 0) # Display architectures. self.data['order'] = order self.data['desc'] = desc self.data['architecture'] = self.get_architecture( context, architecture_id) self.data['architectures'] = self.get_architectures( context, order, desc) elif action == 'architectures-post-add': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. architecture = { 'name': context.req.args.get('name'), 'description': context.req.args.get('description') } # Add architecture. self.add_architecture(context, architecture) elif action == 'architectures-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. architecture_id = context.req.args.get('id') architecture = { 'name': context.req.args.get('name'), 'description': context.req.args.get('description') } # Add architecture. self.edit_architecture(context, architecture_id, architecture) elif action == 'architectures-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected architectures. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete architectures. if selection: for architecture_id in selection: self.delete_architecture(context, architecture_id) elif action == 'admin-platforms-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. order = context.req.args.get('order') or self.platform_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.platform_sort_direction == 'desc' platform_id = int(context.req.args.get('platform') or 0) # Display platforms. self.data['order'] = order self.data['desc'] = desc self.data['platform'] = self.get_platform(context, platform_id) self.data['platforms'] = self.get_platforms( context, order, desc) elif action == 'platforms-post-add': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. platform = { 'name': context.req.args.get('name'), 'description': context.req.args.get('description') } # Add platform. self.add_platform(context, platform) elif action == 'platforms-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. platform_id = context.req.args.get('id') platform = { 'name': context.req.args.get('name'), 'description': context.req.args.get('description') } # Add platform. self.edit_platform(context, platform_id, platform) elif action == 'platforms-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected platforms. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete platforms. if selection: for platform_id in selection: self.delete_platform(context, platform_id) elif action == 'admin-types-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values order = context.req.args.get('order') or self.type_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.type_sort_direction == 'desc' platform_id = int(context.req.args.get('type') or 0) # Display platforms. self.data['order'] = order self.data['desc'] = desc self.data['type'] = self.get_type(context, platform_id) self.data['types'] = self.get_types(context, order, desc) elif action == 'types-post-add': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. type = { 'name': context.req.args.get('name'), 'description': context.req.args.get('description') } # Add type. self.add_type(context, type) elif action == 'types-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. type_id = context.req.args.get('id') type = { 'name': context.req.args.get('name'), 'description': context.req.args.get('description') } # Add platform. self.edit_type(context, type_id, type) elif action == 'types-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected types. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete types. if selection: for type_id in selection: self.delete_type(context, type_id)
def _do_actions(self, context, actions, req_data): for action in actions: if action == 'get-file': context.req.perm.require('DOWNLOADS_VIEW') # Get request arguments. download_id = context.req.args.get('id') or 0 download_file = context.req.args.get('file') # Get download. if download_id: download = self.get_download(context, download_id) else: download = self.get_download_by_file(context, download_file) # Check if requested download exists. if not download: raise TracError('File not found.') # Check resource based permission. context.req.perm.require('DOWNLOADS_VIEW', Resource('downloads', download['id'])) filename = os.path.basename(download['file']) # Get download file path. path = os.path.normpath(os.path.join(self.path, to_unicode(download['id']), filename)) self.log.debug('path: %s' % (path,)) # Increase downloads count. new_download = {'count' : download['count'] + 1} # Edit download. self.edit_download(context, download['id'], new_download) # Notify change listeners. for listener in self.change_listeners: listener.download_changed(context, new_download, download) # Commit DB before file send. db = self.env.get_db_cnx() db.commit() # Guess mime type. file = open(path.encode('utf-8'), "r") file_data = file.read(1000) file.close() mimeview = Mimeview(self.env) mime_type = mimeview.get_mimetype(path, 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 # Return uploaded file to request. context.req.send_header('Content-Disposition', 'attachment;filename="%s"' % (os.path.normpath(download['file']))) context.req.send_header('Content-Description', download['description']) try: context.req.send_file(path.encode('utf-8'), mime_type) except RequestDone: try: for listener in self.download_listeners: listener.downloaded(context, download) finally: raise RequestDone elif action == 'downloads-list': context.req.perm.require('DOWNLOADS_VIEW') # Get form values. order = context.req.args.get('order') or self.download_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.download_sort_direction req_data['order'] = order req_data['desc'] = desc req_data['has_tags'] = self.env.is_component_enabled('tractags.api.TagEngine') req_data['visible_fields'] = self.visible_fields req_data['title'] = self.title req_data['description'] = self.get_description(context) req_data['downloads'] = self.get_downloads(context, order, desc) req_data['visible_fields'] = [visible_field for visible_field in self.visible_fields] # Component, versions, etc. are needed only for new download # add form. if context.req.perm.has_permission('DOWNLOADS_ADD'): req_data['components'] = self.get_components(context) req_data['versions'] = self.get_versions(context) req_data['platforms'] = self.get_platforms(context) req_data['types'] = self.get_types(context) elif action == 'admin-downloads-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values order = context.req.args.get('order') or self.download_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.download_sort_direction download_id = safe_int(context.req.args.get('download', '0')) req_data['supported_files'] = ', '.join(self.ext) req_data['order'] = order req_data['desc'] = desc req_data['has_tags'] = self.env.is_component_enabled('tractags.api.TagEngine') req_data['download'] = self.get_download(context, download_id) req_data['downloads'] = self.get_downloads(context, order, desc) req_data['components'] = self.get_components(context) req_data['versions'] = self.get_versions(context) req_data['platforms'] = self.get_platforms(context) req_data['types'] = self.get_types(context) if not req_data['components']: req_data['cstate'] = {'disabled': 'disabled'} if not req_data['versions']: req_data['vstate'] = {'disabled': 'disabled'} if not req_data['platforms']: req_data['pstate'] = {'disabled': 'disabled'} if not req_data['types']: req_data['tstate'] = {'disabled': 'disabled'} elif action == 'description-edit': context.req.perm.require('DOWNLOADS_ADMIN') elif action == 'description-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. description = context.req.args.get('description') # Set new description. self.edit_description(context, description) elif action == 'downloads-post-add': context.req.perm.require('DOWNLOADS_ADD') # Get form values. file, filename, file_size = self._get_file_from_req(context) download = {'file' : filename, 'description' : context.req.args.get('description'), 'size' : file_size, 'time' : to_timestamp(datetime.now(utc)), 'count' : 0, 'author' : context.req.authname, 'tags' : context.req.args.get('tags'), 'component' : context.req.args.get('component'), 'version' : context.req.args.get('version'), 'platform' : context.req.args.get('platform'), 'type' : context.req.args.get('type')} # Upload file to DB and file storage. self._add_download(context, download, file) # Close input file. file.close() elif action == 'downloads-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. download_id = safe_int(context.req.args.get('id')) old_download = self.get_download(context, download_id) download = {'description' : context.req.args.get('description'), 'tags' : context.req.args.get('tags'), 'component' : context.req.args.get('component'), 'version' : context.req.args.get('version'), 'platform' : context.req.args.get('platform'), 'type' : context.req.args.get('type')} try: # NOTE: if only description changed, file cannot be found and this raises TracError file, filename, file_size = self._get_file_from_req(context) if old_download['file'] != filename or old_download['size'] != file_size: download['file'] = filename download['size'] = file_size download['author'] = context.req.authname download['time'] = to_timestamp(datetime.now(utc)) self._add_download(context, download, file, {'id': download_id, 'file': old_download['file']}) else: # Edit Download. self.edit_download(context, download_id, download) except: # Edit Download. self.edit_download(context, download_id, download) finally: # Close input file. if 'file' in locals(): file.close() # Notify change listeners. for listener in self.change_listeners: listener.download_changed(context, download, old_download) elif action == 'downloads-featured': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected downloads. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] if selection: self.clean_featured(context) self.edit_featured(context, selection) elif action == 'downloads-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected downloads. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete download. if selection: for download_id in selection: download_id = safe_int(download_id) download = self.get_download(context, download_id) self.log.debug('download: %s' % (download,)) self._delete_download(context, download) elif action == 'admin-platforms-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. order = context.req.args.get('order') or self.platform_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.platform_sort_direction platform_id = safe_int(context.req.args.get('platform','0')) if order not in self.platform_sort_options: raise TracError('Invalid sort order') # Display platforms. req_data['order'] = order req_data['desc'] = desc req_data['platform'] = self.get_platform(context, platform_id) req_data['platforms'] = self.get_platforms(context, order, desc) elif action == 'platforms-post-add': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. platform = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description')} # Add platform. self.add_platform(context, platform) elif action == 'platforms-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. platform_id = context.req.args.get('id') platform = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description')} # Add platform. self.edit_platform(context, platform_id, platform) elif action == 'platforms-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected platforms. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete platforms. if selection: for platform_id in selection: platform_id = safe_int(platform_id) self.delete_platform(context, platform_id) elif action == 'admin-types-list': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values order = context.req.args.get('order') or self.type_sort if order not in self.type_sort_options: self.log.debug('Invalid order option: %s' % order) order = self.type_sort if context.req.args.has_key('desc'): desc = context.req.args.get('desc') == '1' else: desc = self.type_sort_direction platform_id = safe_int(context.req.args.get('type','0')) # Display platforms. req_data['order'] = order req_data['desc'] = desc req_data['type'] = self.get_type(context, platform_id) req_data['types'] = self.get_types(context, order, desc) elif action == 'types-post-add': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. type = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description')} # Add type. self.add_type(context, type) elif action == 'types-post-edit': context.req.perm.require('DOWNLOADS_ADMIN') # Get form values. type_id = safe_int(context.req.args.get('id')) type = {'name' : context.req.args.get('name'), 'description' : context.req.args.get('description')} # Add platform. self.edit_type(context, type_id, type) elif action == 'types-delete': context.req.perm.require('DOWNLOADS_ADMIN') # Get selected types. selection = context.req.args.get('selection') if isinstance(selection, (str, unicode)): selection = [selection] # Delete types. if selection: for type_id in selection: type_id = safe_int(type_id) self.delete_type(context, type_id)
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
def send_backlog_as(env, req, backlog, format): "This method will handle the request completely, will not return" mime = Mimeview(env) mime.send_converted(req, BACKLOG_CONVERSION_KEY, backlog, format, filename=backlog.scope)
def _do_actions(self, context, actions): api = TrackerApi() time_interval = self.env.config.getint('tracker', 'time_interval', 10) time_separate = 1 minutes_interval=0 screenshotsWithHourse = [] screenshotsWithMinutes = [] template_hourse = [] minute = 0 min_hourse = 0 max_hourse = 0 allScreenshots=[] for action in actions: if action == 'view': date = datetime.datetime.now(context.req.tz) if 'date' in context.req.args: date_from_calendar = context.req.args['date'].strip() if date_from_calendar: precisedate = user_time(context.req, parse_date, date_from_calendar) date = precisedate.astimezone(context.req.tz) to_date = to_datetime(datetime.datetime(date.year, date.month, date.day, 23, 59, 59, 999999), context.req.tz) to_date_timestamp = to_timestamp(to_date) full_date = { 'from_date': to_date_timestamp - 86400, 'to_date' : to_date_timestamp } context.req.data['fromdate'] = to_date context.req.data['username'] = context.req.args.get('username') screenshot_id = int(context.req.args.get('id') or 0) screenshots = api.get_screenshots(context, context.req.args.get('username'), full_date) context.req.data['id'] = screenshot_id for hourse in range(0, 24): for screenshot in screenshots: screenshot["hourse"] = datetime.datetime.fromtimestamp(screenshot["time"]).strftime('%H') if (int(screenshot["hourse"]) == hourse): if min_hourse == 0: min_hourse = hourse elif min_hourse > hourse: min_hourse = hourse if max_hourse < hourse: max_hourse = hourse screenshotsWithHourse.append({hourse:screenshot}) while (minute <= 59): for screenshotsAll in screenshotsWithHourse: for index in screenshotsAll: screenshotMinute = datetime.datetime.fromtimestamp(float(screenshotsAll[index]["time"])).strftime('%M') if int(screenshotMinute) == minute: screenshotHourse = datetime.datetime.fromtimestamp(screenshotsAll[index]["time"]).strftime('%H') if int(screenshotHourse) not in template_hourse: template_hourse.append(int(screenshotHourse)) screenshotsAll[index]['hourse'] = int(screenshotHourse) screenshotsAll[index]['minute'] = int(screenshotMinute) if len(screenshotsWithMinutes)>0 and screenshotsWithMinutes[0]['minute']==screenshotsAll[index]['minute']: screenshotsWithMinutes.pop() screenshotsWithMinutes.append(screenshotsAll[index]) minute += 10 for hourse in template_hourse: for screenshot in screenshotsWithMinutes: if screenshot['hourse']==hourse: while screenshot['minute']!=minutes_interval: allScreenshots.append({"hourse":hourse,"screen":None,"minute":minutes_interval}) minutes_interval+=10 screenshot["screen"]=1 allScreenshots.append(screenshot) minutes_interval+=10 while (minutes_interval!=60): allScreenshots.append({"hourse":hourse,"screen":None,"minute":minutes_interval}) minutes_interval+=10 minutes_interval=0 context.req.data['allScreenshots'] = allScreenshots context.req.data['template_hourse'] = range(int(min_hourse), int(max_hourse)+time_separate) context.req.data['time_interval'] = time_interval context.req.data['time_separate'] = time_separate context.req.data['template'] = 'user_worklog_view.html' add_stylesheet(context.req, 'trac/css/tracker.css') chrome = Chrome(self.env) chrome.add_jquery_ui(context.req) return 'screenshots', None if action == 'get-file': screenshot_id = int(context.req.args.get('id') or 0) format = context.req.args.get('format') or self.default_format screenshot = api.get_screenshot(context, screenshot_id) if format == 'html': context.req.data['screenshot'] = screenshot return 'screenshot', None else: screenshot_path = screenshot[0]['path'] filename = self.path + '/' + screenshot_path 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 context.req.send_file(filename.encode('utf-8'), mime_type) elif action == 'get-users': context.req.data['users'] = api.get_users(context) context.req.data['template'] = 'user_list.html' context.req.data['client'] = {'download_href': 'jar-tracker/' + calculate_client_package_name()} return 'screenshots', None else: return 'screenshots', None
def mimeview_formatter(req, text): mimeview = Mimeview(self.env) context = Context.from_request(req) return mimeview.render(context, mimetype, text)
def _get_userlog(self, req, db, user, sort): mimeview = Mimeview(self.env) repos = self.env.get_repository() diff_options = get_diff_options(req) cursor = db.cursor() cursor.execute("SELECT rev, time, message FROM revision " "WHERE author='%s' ORDER BY time %s" % (user, sort)) # Have to sort by time because rev is a text field # and sorts lexicographically rather than numerically changesets = [] for rev, time, message in cursor: if self.wiki_format_messages: message = wiki_to_html(message, self.env, req, escape_newlines=True) else: message = html.PRE(message) prev = repos.get_node('/', rev).get_previous() if prev: prev_rev = prev[1] else: prev_rev = rev diffs = [] changes = repos.get_changes(old_path='/', old_rev=prev_rev, new_path='/', new_rev=rev) for old_node, new_node, kind, change in changes: if kind == Node.DIRECTORY: if change == Changeset.ADD: diffs.append(('%s added' % new_node.path, '')) elif change == Changeset.DELETE: diffs.append(('%s deleted' % old_node.path, '')) continue new_content = old_content = '' new_node_info = old_node_info = ('','') if old_node: old_content = old_node.get_content().read() if is_binary(old_content): continue old_node_info = (old_node.path, old_node.rev) old_content = mimeview.to_unicode(old_content, old_node.content_type) if new_node: new_content = new_node.get_content().read() if is_binary(new_content): continue new_node_info = (new_node.path, new_node.rev) new_path = new_node.path new_content = mimeview.to_unicode(new_content, new_node.content_type) else: old_node_path = repos.normalize_path(old_node.path) diff_old_path = repos.normalize_path('/') new_path = posixpath.join('/', old_node_path[len(diff_old_path)+1:]) if old_content != new_content: context = 3 options = diff_options[1] for option in options: if option.startswith('-U'): context = int(option[2:]) break if not old_node_info[0]: old_node_info = new_node_info # support for 'A'dd changes diff = 'Index: ' + new_path + CRLF diff += '=' * 67 + CRLF diff += '--- %s (revision %s)' % old_node_info + CRLF diff += '+++ %s (revision %s)' % new_node_info + CRLF for line in unified_diff(old_content.splitlines(), new_content.splitlines(), context, ignore_blank_lines='-B' in options, ignore_case='-i' in options, ignore_space_changes='-b' in options): diff += line + CRLF if change == Changeset.ADD: diffs.append(('%s added' % (new_node.path,), diff)) elif change == Changeset.DELETE: diffs.append(('%s deleted' % (old_node.path,), diff)) else: diffs.append(('%s edited' % (new_node.path,), diff)) changesets.append((int(rev), format_datetime(time), message, diffs)) return changesets
def _render_file(self, req, repos, node, rev=None): req.perm.assert_permission('FILE_VIEW') changeset = repos.get_changeset(node.rev) req.hdf['file'] = { 'rev': node.rev, 'changeset_href': util.escape(self.env.href.changeset(node.rev)), 'date': time.strftime('%x %X', time.localtime(changeset.date)), 'age': util.pretty_timedelta(changeset.date), 'author': changeset.author or 'anonymous', 'message': wiki_to_html(changeset.message or '--', self.env, req, escape_newlines=True) } mime_type = node.content_type if not mime_type or mime_type == 'application/octet-stream': mime_type = get_mimetype(node.name) or mime_type or 'text/plain' # We don't have to guess if the charset is specified in the # svn:mime-type property ctpos = mime_type.find('charset=') if ctpos >= 0: charset = mime_type[ctpos + 8:] else: charset = None format = req.args.get('format') if format in ['raw', 'txt']: req.send_response(200) req.send_header('Content-Type', format == 'txt' and 'text/plain' or mime_type) req.send_header('Content-Length', node.content_length) req.send_header('Last-Modified', util.http_date(node.last_modified)) req.end_headers() content = node.get_content() while 1: chunk = content.read(CHUNK_SIZE) if not chunk: raise RequestDone req.write(chunk) else: # Generate HTML preview max_preview_size = int( self.config.get('mimeviewer', 'max_preview_size', '262144')) content = node.get_content().read(max_preview_size) max_size_reached = len(content) == max_preview_size if not charset: charset = detect_unicode(content) or \ self.config.get('trac', 'default_charset') if not is_binary(content): content = util.to_utf8(content, charset) if mime_type != 'text/plain': plain_href = self.env.href.browser(node.path, rev=rev and node.rev, format='txt') add_link(req, 'alternate', plain_href, 'Plain Text', 'text/plain') if max_size_reached: req.hdf['file.max_file_size_reached'] = 1 req.hdf['file.max_file_size'] = max_preview_size preview = ' ' else: preview = Mimeview(self.env).render(req, mime_type, content, node.name, node.rev, annotations=['lineno']) req.hdf['file.preview'] = preview raw_href = self.env.href.browser(node.path, rev=rev and node.rev, format='raw') req.hdf['file.raw_href'] = util.escape(raw_href) add_link(req, 'alternate', raw_href, 'Original Format', mime_type) add_stylesheet(req, 'common/css/code.css')
def render_admin_panel(self, req, cat, page, version): # here comes the page content, handling, etc. data = {} if req.method == "POST": submit = req.args.get('submit').strip() if submit == 'Add': # Get form values. #file = req.args['download'] # Test if file is uploaded. #if hasattr(file, 'filename'): # self.log.debug("Filename:" + file.filename) file, filename, file_size = self.get_file_from_req(req) download = { 'file': filename, 'description': req.args.get('description'), 'size': file_size, 'time': to_timestamp(datetime.datetime.now(utc)), 'count': 0, 'author': req.authname } self.log.debug("FileUpload filename:" + download['file']) self.log.debug("FileUpload description:" + download['description']) self.log.debug("FileUpload size:", download['size']) self.log.debug("FileUpload time:", download['time']) self.log.debug("FileUpload author:" + download['author']) # Upload file to DB and file storage. add_download(download, file) file.close() add_notice(req, 'Download has been added.') elif submit == 'Remove': ids = req.args.getlist('sels') if ids is not None and len(ids) > 0: for id in ids: sql = "DELETE FROM download WHERE id ={}".format( int(id)) self.env.db_transaction(sql) add_notice(req, 'Download has been deleted.') else: # Get download. download_id = req.args.get('sel') or 0 if download_id > 0: sql = "SELECT file, description FROM download where id={}".format( download_id) cursor = self.env.db_query(sql) if len(cursor) > 0: fn = cursor[0][0] description = cursor[0][1] else: raise TracError("File not found.") # Get download file path. filename = os.path.basename(fn) filepath = os.path.join(self.path, to_unicode(download_id), filename) filepath = os.path.normpath(filepath) # Increase downloads count. sql = "UPDATE download SET count=count+1 WHERE id ={}".format( download_id) self.env.db_transaction(sql) # Guess mime type. with open(filepath.encode('utf-8'), 'r') as fileobj: file_data = fileobj.read(1000) mimeview = Mimeview(self.env) mime_type = mimeview.get_mimetype(filepath, 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 # Return uploaded file to request. req.send_header( 'Content-Disposition', 'attachment;filename="%s"' % os.path.normpath(fn)) req.send_header('Content-Description', description) req.send_file(filepath.encode('utf-8'), mime_type) cursor = self.env.db_query( "SELECT id, file, description, size, time, author FROM download ORDER BY id" ) data['downloads'] = [(row[0], row[1], row[2]) for row in cursor] return ('admin_download.html', data, None)
def _do_actions(self, context, actions): api = TrackerApi() time_interval = self.env.config.getint('tracker', 'time_interval', 10) time_separate = 1 minutes_interval = 0 screenshotsWithHourse = [] screenshotsWithMinutes = [] template_hourse = [] minute = 0 min_hourse = 0 max_hourse = 0 allScreenshots = [] for action in actions: if action == 'view': date = datetime.datetime.now(context.req.tz) if 'date' in context.req.args: date_from_calendar = context.req.args['date'].strip() if date_from_calendar: precisedate = user_time(context.req, parse_date, date_from_calendar) date = precisedate.astimezone(context.req.tz) to_date = to_datetime( datetime.datetime(date.year, date.month, date.day, 23, 59, 59, 999999), context.req.tz) to_date_timestamp = to_timestamp(to_date) full_date = { 'from_date': to_date_timestamp - 86400, 'to_date': to_date_timestamp } context.req.data['fromdate'] = to_date context.req.data['username'] = context.req.args.get('username') screenshot_id = int(context.req.args.get('id') or 0) screenshots = api.get_screenshots( context, context.req.args.get('username'), full_date) context.req.data['id'] = screenshot_id for hourse in range(0, 24): for screenshot in screenshots: screenshot["hourse"] = datetime.datetime.fromtimestamp( screenshot["time"]).strftime('%H') if (int(screenshot["hourse"]) == hourse): if min_hourse == 0: min_hourse = hourse elif min_hourse > hourse: min_hourse = hourse if max_hourse < hourse: max_hourse = hourse screenshotsWithHourse.append({hourse: screenshot}) while (minute <= 59): for screenshotsAll in screenshotsWithHourse: for index in screenshotsAll: screenshotMinute = datetime.datetime.fromtimestamp( float(screenshotsAll[index]["time"])).strftime( '%M') if int(screenshotMinute) == minute: screenshotHourse = datetime.datetime.fromtimestamp( screenshotsAll[index]["time"]).strftime( '%H') if int(screenshotHourse ) not in template_hourse: template_hourse.append( int(screenshotHourse)) screenshotsAll[index]['hourse'] = int( screenshotHourse) screenshotsAll[index]['minute'] = int( screenshotMinute) if len(screenshotsWithMinutes ) > 0 and screenshotsWithMinutes[0][ 'minute'] == screenshotsAll[index][ 'minute']: screenshotsWithMinutes.pop() screenshotsWithMinutes.append( screenshotsAll[index]) minute += 10 for hourse in template_hourse: for screenshot in screenshotsWithMinutes: if screenshot['hourse'] == hourse: while screenshot['minute'] != minutes_interval: allScreenshots.append({ "hourse": hourse, "screen": None, "minute": minutes_interval }) minutes_interval += 10 screenshot["screen"] = 1 allScreenshots.append(screenshot) minutes_interval += 10 while (minutes_interval != 60): allScreenshots.append({ "hourse": hourse, "screen": None, "minute": minutes_interval }) minutes_interval += 10 minutes_interval = 0 context.req.data['allScreenshots'] = allScreenshots context.req.data['template_hourse'] = range( int(min_hourse), int(max_hourse) + time_separate) context.req.data['time_interval'] = time_interval context.req.data['time_separate'] = time_separate context.req.data['template'] = 'user_worklog_view.html' add_stylesheet(context.req, 'trac/css/tracker.css') chrome = Chrome(self.env) chrome.add_jquery_ui(context.req) return 'screenshots', None if action == 'get-file': screenshot_id = int(context.req.args.get('id') or 0) format = context.req.args.get('format') or self.default_format screenshot = api.get_screenshot(context, screenshot_id) if format == 'html': context.req.data['screenshot'] = screenshot return 'screenshot', None else: screenshot_path = screenshot[0]['path'] filename = self.path + '/' + screenshot_path 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 context.req.send_file(filename.encode('utf-8'), mime_type) elif action == 'get-users': context.req.data['users'] = api.get_users(context) context.req.data['template'] = 'user_list.html' context.req.data['client'] = { 'download_href': 'jar-tracker/' + calculate_client_package_name() } return 'screenshots', None else: return 'screenshots', None
def _render_file(self, req, repos, node, rev=None): req.perm.assert_permission('FILE_VIEW') mimeview = Mimeview(self.env) # MIME type detection content = node.get_content() chunk = content.read(CHUNK_SIZE) mime_type = node.content_type if not mime_type or mime_type == 'application/octet-stream': mime_type = mimeview.get_mimetype(node.name, chunk) or \ mime_type or 'text/plain' # Eventually send the file directly format = req.args.get('format') if format in ['raw', 'txt']: req.send_response(200) req.send_header('Content-Type', format == 'txt' and 'text/plain' or mime_type) req.send_header('Content-Length', node.content_length) req.send_header('Last-Modified', http_date(node.last_modified)) if not self.render_unsafe_content: # Force browser to download files instead of rendering # them, since they might contain malicious code enabling # XSS attacks req.send_header('Content-Disposition', 'attachment') req.end_headers() while 1: if not chunk: raise RequestDone req.write(chunk) chunk = content.read(CHUNK_SIZE) else: # The changeset corresponding to the last change on `node` # is more interesting than the `rev` changeset. changeset = repos.get_changeset(node.rev) message = changeset.message or '--' if self.config['changeset'].getbool('wiki_format_messages'): message = wiki_to_html(message, self.env, req, escape_newlines=True) else: message = html.PRE(message) ZhUnit = { 'second': u'秒', 'seconds': u'秒', 'minute': u'分钟', 'minutes': u'分钟', 'hour': u'小时', 'hours': u'小时', 'day': u'天', 'days': u'天', 'year': u'年', 'years': u'年', 'month': u'月', 'months': u'月' } tempTime = pretty_timedelta(changeset.date) numAndUnit = tempTime.split(' ') numAndUnit[1] = ZhUnit.get(numAndUnit[1], numAndUnit[1]) ZhAge = ' '.join(numAndUnit) req.hdf['file'] = { 'rev': node.rev, 'changeset_href': req.href.changeset(node.rev), 'date': format_datetime(changeset.date), 'age': ZhAge, 'size': pretty_size(node.content_length), 'author': changeset.author or 'anonymous', 'message': message } # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != 'text/plain': plain_href = req.href.browser(node.path, rev=rev, format='txt') add_link(req, 'alternate', plain_href, 'Plain Text', 'text/plain') # add ''Original Format'' alternate link (always) raw_href = req.href.browser(node.path, rev=rev, format='raw') add_link(req, 'alternate', raw_href, 'Original Format', mime_type) self.log.debug( "Rendering preview of node %s@%s with mime-type %s" % (node.name, str(rev), mime_type)) del content # the remainder of that content is not needed req.hdf['file'] = mimeview.preview_to_hdf( req, node.get_content(), node.get_content_length(), mime_type, node.created_path, raw_href, annotations=['lineno']) add_stylesheet(req, 'common/css/code.css')
def _render_diff(self, req, filename, repos, data): """Raw Unified Diff version""" req.send_response(200) req.send_header('Content-Type', 'text/x-patch;charset=utf-8') req.send_header('Content-Disposition', content_disposition('inline', filename + '.diff')) buf = StringIO() mimeview = Mimeview(self.env) for old_node, new_node, kind, change in repos.get_changes( new_path=data['new_path'], new_rev=data['new_rev'], old_path=data['old_path'], old_rev=data['old_rev']): # TODO: Property changes # Content changes if kind == Node.DIRECTORY: continue new_content = old_content = '' new_node_info = old_node_info = ('','') mimeview = Mimeview(self.env) if old_node: if mimeview.is_binary(old_node.content_type, old_node.path): continue old_content = old_node.get_content().read() if mimeview.is_binary(content=old_content): continue old_node_info = (old_node.path, old_node.rev) old_content = mimeview.to_unicode(old_content, old_node.content_type) if new_node: if mimeview.is_binary(new_node.content_type, new_node.path): continue new_content = new_node.get_content().read() if mimeview.is_binary(content=new_content): continue new_node_info = (new_node.path, new_node.rev) new_path = new_node.path new_content = mimeview.to_unicode(new_content, new_node.content_type) else: old_node_path = repos.normalize_path(old_node.path) diff_old_path = repos.normalize_path(data['old_path']) new_path = posixpath.join(data['new_path'], old_node_path[len(diff_old_path)+1:]) if old_content != new_content: options = data['diff']['options'] context = options.get('contextlines', 3) if context < 0: context = 3 # FIXME: unified_diff bugs with context=None ignore_blank_lines = options.get('ignoreblanklines') ignore_case = options.get('ignorecase') ignore_space = options.get('ignorewhitespace') if not old_node_info[0]: old_node_info = new_node_info # support for 'A'dd changes buf.write('Index: ' + new_path + CRLF) buf.write('=' * 67 + CRLF) buf.write('--- %s\t(revision %s)' % old_node_info + CRLF) buf.write('+++ %s\t(revision %s)' % new_node_info + CRLF) for line in unified_diff(old_content.splitlines(), new_content.splitlines(), context, ignore_blank_lines=ignore_blank_lines, ignore_case=ignore_case, ignore_space_changes=ignore_space): buf.write(line + CRLF) diff_str = buf.getvalue().encode('utf-8') req.send_header('Content-Length', len(diff_str)) req.end_headers() req.write(diff_str) raise RequestDone
def mimeview_formatter(req, text): mimeview = Mimeview(self.env) context = web_context(req) return mimeview.render(context, mimetype, text)
def _render_file(self, req, repos, node, rev=None): req.perm.assert_permission('FILE_VIEW') mimeview = Mimeview(self.env) # MIME type detection content = node.get_content() chunk = content.read(CHUNK_SIZE) mime_type = node.content_type if not mime_type or mime_type == 'application/octet-stream': mime_type = mimeview.get_mimetype(node.name, chunk) or \ mime_type or 'text/plain' # Eventually send the file directly format = req.args.get('format') if format in ['raw', 'txt']: req.send_response(200) req.send_header('Content-Type', format == 'txt' and 'text/plain' or mime_type) req.send_header('Content-Length', node.content_length) req.send_header('Last-Modified', http_date(node.last_modified)) req.end_headers() while 1: if not chunk: raise RequestDone req.write(chunk) chunk = content.read(CHUNK_SIZE) else: # The changeset corresponding to the last change on `node` # is more interesting than the `rev` changeset. changeset = repos.get_changeset(node.rev) message = changeset.message or '--' if self.config['changeset'].getbool('wiki_format_messages'): message = wiki_to_html(message, self.env, req, escape_newlines=True) else: message = html.PRE(message) req.hdf['file'] = { 'rev': node.rev, 'changeset_href': req.href.changeset(node.rev), 'date': format_datetime(changeset.date), 'age': pretty_timedelta(changeset.date), 'size': pretty_size(node.content_length), 'author': changeset.author or 'anonymous', 'message': message } # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != 'text/plain': plain_href = req.href.browser(node.path, rev=rev, format='txt') add_link(req, 'alternate', plain_href, 'Plain Text', 'text/plain') # add ''Original Format'' alternate link (always) raw_href = req.href.browser(node.path, rev=rev, format='raw') add_link(req, 'alternate', raw_href, u'Format original', mime_type) self.log.debug("Rendering preview of node %s@%s with mime-type %s" % (node.name, str(rev), mime_type)) del content # the remainder of that content is not needed req.hdf['file'] = mimeview.preview_to_hdf( req, node.get_content(), node.get_content_length(), mime_type, node.created_path, raw_href, annotations=['lineno']) add_stylesheet(req, 'common/css/code.css')