def process_request(self, req): stylespec = (req.args.get('ss_mod'), req.args.get('ss_id'), req.args.get('ss_fil')) docspec = (req.args.get('doc_mod'), req.args.get('doc_id'), req.args.get('doc_fil')) if None in stylespec or None in docspec: self.env.log.error("Missing request parameters: %s", req.args) raise TracError('Bad request') style_obj = self._get_src(self.env, req, *stylespec) doc_obj = self._get_src(self.env, req, *docspec) params = dict(self._get_opts(req.args, 'xp_')) lastmod = max(style_obj.get_last_modified(), doc_obj.get_last_modified()) req.check_modified(lastmod) if not req.get_header('If-None-Match'): if http_date(lastmod) == req.get_header('If-Modified-Since'): req.send_response(304) req.end_headers() raise RequestDone req.send_header('Last-Modified', http_date(lastmod)) page, content_type = self._transform(style_obj, doc_obj, params, self.env, req) req.send_response(200) req.send_header('Content-Type', content_type + ';charset=utf-8') req.send_header('Content-Length', len(page)) req.end_headers() if req.method != 'HEAD': req.write(page) raise RequestDone
def process_request(plugin, req): """Renders a svg graph based on request attributes and returns a http response (or traceback in case of error)""" class MyDebug: out = "" def write(self, data): self.out += data import tractimevisualizerplugin debug = None; if tractimevisualizerplugin.DEVELOPER_MODE: debug = MyDebug() try: from trac.web import RequestDone from trac.util.datefmt import http_date from time import time req.send_response(200) req.send_header('Content-Type', "image/svg+xml") req.send_header('Last-Modified', http_date(time())) req.end_headers() if req.method != 'HEAD': db = plugin.env.get_db_cnx() req.write(build_svg(db, req.args, debug)) raise RequestDone finally: if debug: plugin.log.debug(debug.out)
def check_modified(self, datetime, extra=''): """Check the request "If-None-Match" header against an entity tag. The entity tag is generated from the specified last modified time (`datetime`), optionally appending an `extra` string to indicate variants of the requested resource. That `extra` parameter can also be a list, in which case the MD5 sum of the list content will be used. If the generated tag matches the "If-None-Match" header of the request, this method sends a "304 Not Modified" response to the client. Otherwise, it adds the entity tag as an "ETag" header to the response so that consecutive requests can be cached. """ if isinstance(extra, list): m = md5() for elt in extra: m.update(repr(elt)) extra = m.hexdigest() etag = 'W/"%s/%s/%s"' % (self.authname, http_date(datetime), extra) inm = self.get_header('If-None-Match') if not inm or inm != etag: self.send_header('ETag', etag) else: self.send_response(304) self.send_header('Content-Length', 0) self.end_headers() raise RequestDone
def process_request(plugin, req): """Renders a svg graph based on request attributes and returns a http response (or traceback in case of error)""" class MyDebug: out = "" def write(self, data): self.out += data import tractimevisualizerplugin debug = None if tractimevisualizerplugin.DEVELOPER_MODE: debug = MyDebug() try: #print>>debug, dir(req) from trac.web import RequestDone from trac.util.datefmt import http_date from time import time req.send_response(200) req.send_header('Content-Type', "image/svg+xml") req.send_header('Last-Modified', http_date(time())) req.end_headers() if req.method != 'HEAD': db = plugin.env.get_db_cnx() args = req.args.copy() args['calc_fields'] = plugin.env.config.get( 'timevisualizer', 'calc_fields', 'estimatedhours-totalhours') req.write(build_svg(db, args, debug)) raise RequestDone finally: if debug: plugin.log.debug(debug.out)
def check_modified(self, datetime, extra=''): """Check the request "If-None-Match" header against an entity tag. The entity tag is generated from the specified last modified time (`datetime`), optionally appending an `extra` string to indicate variants of the requested resource. That `extra` parameter can also be a list, in which case the MD5 sum of the list content will be used. If the generated tag matches the "If-None-Match" header of the request, this method sends a "304 Not Modified" response to the client. Otherwise, it adds the entity tag as an "ETag" header to the response so that consecutive requests can be cached. """ if isinstance(extra, list): m = md5() for elt in extra: m.update(repr(elt)) extra = m.hexdigest() etag = 'W/"%s/%s/%s"' % (self.authname, http_date(datetime), extra) inm = self.get_header('If-None-Match') if (not inm or inm != etag): self.send_header('ETag', etag) else: self.send_response(304) self.send_header('Content-Length', 0) self.end_headers() raise RequestDone
def export_rss(self, req, query): query.verbose = True db = self.env.get_db_cnx() results = query.execute(req, db) for result in results: result['href'] = req.abs_href.ticket(result['id']) if result['reporter'].find('@') == -1: result['reporter'] = '' if result['description']: # unicode() cancels out the Markup() returned by wiki_to_html descr = wiki_to_html(result['description'], self.env, req, db, absurls=True) result['description'] = unicode(descr) if result['time']: result['time'] = http_date(result['time']) req.hdf['query.results'] = results req.hdf['query.href'] = req.abs_href.query( group=query.group, groupdesc=query.groupdesc and 1 or None, verbose=query.verbose and 1 or None, **query.constraints) return (req.hdf.render('query_rss.cs'), 'application/rss+xml')
def send_file(self, path, mimetype=None): """Send a local file to the browser. This method includes the "Last-Modified", "Content-Type" and "Content-Length" headers in the response, corresponding to the file attributes. It also checks the last modification time of the local file against the "If-Modified-Since" provided by the user agent, and sends a "304 Not Modified" response if it matches. """ if not os.path.isfile(path): raise HTTPNotFound("File %s not found" % path) stat = os.stat(path) last_modified = http_date(stat.st_mtime) if last_modified == self.get_header('If-Modified-Since'): self.send_response(304) self.end_headers() raise RequestDone if not mimetype: mimetype = mimetypes.guess_type(path)[0] or \ 'application/octet-stream' self.send_response(200) self.send_header('Content-Type', mimetype) self.send_header('Content-Length', stat.st_size) self.send_header('Last-Modified', last_modified) self.end_headers() if self.method != 'HEAD': self._response = file(path, 'rb') file_wrapper = self.environ.get('wsgi.file_wrapper') if file_wrapper: self._response = file_wrapper(self._response, 4096) raise RequestDone
def process_request(self, req): style = req.args['style'] try: style_cls = get_style_by_name(style) except ValueError as e: raise HTTPNotFound(e) parts = style_cls.__module__.split('.') filename = resource_filename('.'.join(parts[:-1]), parts[-1] + '.py') mtime = datetime.fromtimestamp(os.path.getmtime(filename), localtz) last_modified = http_date(mtime) if last_modified == req.get_header('If-Modified-Since'): req.send_response(304) req.end_headers() return formatter = HtmlFormatter(style=style_cls) content = u'\n\n'.join([ formatter.get_style_defs('div.code pre'), formatter.get_style_defs('table.code td') ]).encode('utf-8') req.send_response(200) req.send_header('Content-Type', 'text/css; charset=utf-8') req.send_header('Last-Modified', last_modified) req.send_header('Content-Length', len(content)) req.write(content)
def runTest(self): """Test timeline in RSS format.""" pagename = random_unique_camel() self._tester.create_wiki_page(pagename) page = WikiPage(self._testenv.get_trac_environment(), pagename) self._tester.go_to_timeline() tc.follow("RSS Feed") tc.find( r"""<\?xml version="1.0"\?>[\n]+ <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Functional Tests</title> <link>http://127.0.0.1:\d+/timeline</link> <description>Trac Timeline</description> <language>en-US</language> <generator>Trac [^<]+</generator> <image> <title>Functional Tests</title> <url>http://127.0.0.1:\d+/chrome/site/your_project_logo.png</url> <link>http://127.0.0.1:\d+/timeline</link> </image> <item> <title>%(pagename)s created</title> <dc:creator>admin</dc:creator> <pubDate>%(http_date)s</pubDate> <link>http://127.0.0.1:\d+/wiki/%(pagename)s\?version=1</link> <guid isPermaLink="false">http://127.0.0.1:\d+/wiki/%(pagename)s\?version=1/\d+</guid> <description>[^<]+</description> <category>wiki</category> </item> """ % { 'pagename': pagename, 'http_date': http_date(page.time) }, 'ms')
def send_file(self, path, mimetype=None): """Send a local file to the browser. This method includes the "Last-Modified", "Content-Type" and "Content-Length" headers in the response, corresponding to the file attributes. It also checks the last modification time of the local file against the "If-Modified-Since" provided by the user agent, and sends a "304 Not Modified" response if it matches. """ if not os.path.isfile(path): raise HTTPNotFound(u"Fichier %s non trouvé" % path) stat = os.stat(path) last_modified = http_date(stat.st_mtime) if last_modified == self.get_header('If-Modified-Since'): self.send_response(304) self.end_headers() raise RequestDone if not mimetype: mimetype = mimetypes.guess_type(path)[0] or \ 'application/octet-stream' self.send_response(200) self.send_header('Content-Type', mimetype) self.send_header('Content-Length', stat.st_size) self.send_header('Last-Modified', last_modified) self.end_headers() if self.method != 'HEAD': self._response = file(path, 'rb') file_wrapper = self.environ.get('wsgi.file_wrapper') if file_wrapper: self._response = file_wrapper(self._response, 4096) raise RequestDone
def render_zip(req, filename, repos, root_node, iter_nodes): """Send a ZIP file containing the data corresponding to the `nodes` iterable. :type root_node: `~trac.versioncontrol.api.Node` :param root_node: optional ancestor for all the *nodes* :param iter_nodes: callable taking the optional *root_node* as input and generating the `~trac.versioncontrol.api.Node` for which the content should be added into the zip. """ req.send_response(200) req.send_header('Content-Type', 'application/zip') req.send_header('Content-Disposition', content_disposition('inline', filename)) if root_node: req.send_header('Last-Modified', http_date(root_node.last_modified)) root_path = root_node.path.rstrip('/') else: root_path = '' if root_path: root_path += '/' root_name = root_node.name + '/' else: root_name = '' root_len = len(root_path) buf = StringIO() zipfile = ZipFile(buf, 'w', ZIP_DEFLATED) for node in iter_nodes(root_node): if node is root_node: continue path = node.path.strip('/') assert path.startswith(root_path) path = root_name + path[root_len:] kwargs = {'mtime': node.last_modified} data = None if node.isfile: data = node.get_processed_content(eol_hint='CRLF').read() properties = node.get_properties() # Subversion specific if 'svn:special' in properties and data.startswith('link '): data = data[5:] kwargs['symlink'] = True if 'svn:executable' in properties: kwargs['executable'] = True elif node.isdir and path: kwargs['dir'] = True data = '' if data is not None: zipfile.writestr(create_zipinfo(path, **kwargs), data) zipfile.close() zip_str = buf.getvalue() req.send_header("Content-Length", len(zip_str)) req.end_headers() req.write(zip_str) raise RequestDone
def populate_hdf(hdf, env, req=None): """Populate the HDF data set with various information, such as common URLs, project information and request-related information. FIXME: do we really have req==None at times? """ from trac import __version__ hdf['trac'] = { 'version': __version__, 'time': format_datetime(), 'time.gmt': http_date() } hdf['project'] = { 'shortname': os.path.basename(env.path), 'name': env.project_name, 'name_encoded': env.project_name, 'descr': env.project_description, 'footer': Markup(env.project_footer), 'url': env.project_url } if req: hdf['trac.href'] = { 'wiki': req.href.wiki(), 'browser': req.href.browser('/'), 'timeline': req.href.timeline(), 'roadmap': req.href.roadmap(), 'milestone': req.href.milestone(None), 'report': req.href.report(), 'query': req.href.query(), 'newticket': req.href.newticket(), 'search': req.href.search(), 'about': req.href.about(), 'about_config': req.href.about('config'), 'login': req.href.login(), 'logout': req.href.logout(), 'settings': req.href.settings(), 'homepage': 'http://trac.edgewall.org/' } hdf['base_url'] = req.base_url hdf['base_host'] = req.base_url[:req.base_url.rfind(req.base_path)] hdf['cgi_location'] = req.base_path hdf['trac.authname'] = req.authname if req.perm: for action in req.perm.permissions(): req.hdf['trac.acl.' + action] = True for arg in [k for k in req.args.keys() if k]: if isinstance(req.args[arg], (list, tuple)): hdf['args.%s' % arg] = [v for v in req.args[arg]] elif isinstance(req.args[arg], basestring): hdf['args.%s' % arg] = req.args[arg]
def send_file(self, path, mimetype=None, expires=None): """Send a local file to the browser. This method includes the "Last-Modified", "Content-Type" and "Content-Length" headers in the response, corresponding to the file attributes. It also checks the last modification time of the local file against the "If-Modified-Since" provided by the user agent, and sends a "304 Not Modified" response if it matches. """ if not os.path.isfile(path): raise HTTPNotFound(_("File %(path)s not found", path=path)) stat = os.stat(path) mtime = datetime.fromtimestamp(stat.st_mtime, localtz) last_modified = http_date(mtime) if last_modified == self.get_header('If-Modified-Since'): self.send_response(304) self.send_header('Content-Length', 0) self.end_headers() raise RequestDone if not mimetype: mimetype = mimetypes.guess_type(path)[0] or \ 'application/octet-stream' self.send_response(200) self.send_header('Content-Type', mimetype) self.send_header('Content-Length', stat.st_size) self.send_header('Last-Modified', last_modified) if expires is not None: self.send_header('Expires', http_date(expires)) self.end_headers() if self.method != 'HEAD': fileobj = file(path, 'rb') file_wrapper = self.environ.get('wsgi.file_wrapper', _FileWrapper) self._response = file_wrapper(fileobj, 4096) raise RequestDone
def send_file(self, req, download_id): import os from datetime import datetime from trac.util.datefmt import http_date, localtz from trac.web.api import RequestDone from trac.web.wsgi import _FileWrapper import mimetypes Session = session(self.env) download = Session.query(Download).get(download_id) stat = os.stat(download.path) mtime = datetime.fromtimestamp(stat.st_mtime, localtz) last_modified = http_date(mtime) if last_modified == req.get_header('If-Modified-Since'): req.send_response(304) req.end_headers() raise RequestDone mimetype = mimetypes.guess_type(download.path)[0] or 'application/octet-stream' req.send_response(200) req.send_header('Content-Type', mimetype) req.send_header('Content-Length', stat.st_size) req.send_header('Last-Modified', last_modified) req.end_headers() if req.method != 'HEAD': fileobj = file(download.path, 'rb') file_wrapper = req.environ.get('wsgi.file_wrapper', _FileWrapper) buffer = fileobj.read(4096) try: while buffer: print 'inside loop' try: req._write(buffer) buffer = fileobj.read(4096) except EOFError: raise RequestDone except Exception, err: raise err else: download.stats.append(Stat(req.authname)) Session.commit() print 'fooo' print '\n\n\n\nAfter'
def process_request(self, req): # settings panel if not 'style' in req.args: req._no_pygments_stylesheet = True styles = list(get_all_styles()) styles.sort(lambda a, b: cmp(a.lower(), b.lower())) if req.method == 'POST': style = req.args.get('new_style') if style and style in styles: req.session['pygments_style'] = style output = self._highlight('html', self.EXAMPLE, False) req.hdf['output'] = Markup(output) req.hdf['current'] = req.session.get('pygments_style', self.default_style) req.hdf['styles'] = styles req.hdf['pygments_path'] = self.env.href.pygments() return 'pygments_settings.cs', None # provide stylesheet else: style = req.args['style'] parts = style.__module__.split('.') filename = resource_filename('.'.join(parts[:-1]), parts[-1] + '.py') mtime = datetime.utcfromtimestamp(os.path.getmtime(filename)) last_modified = http_date(time.mktime(mtime.timetuple())) if last_modified == req.get_header('If-Modified-Since'): req.send_response(304) req.end_headers() return formatter = HtmlFormatter(style=style) content = u'\n\n'.join([ formatter.get_style_defs('div.code pre'), formatter.get_style_defs('table.code td') ]).encode('utf-8') req.send_response(200) req.send_header('Content-Type', 'text/css; charset=utf-8') req.send_header('Last-Modified', last_modified) req.send_header('Content-Length', len(content)) req.write(content)
def send_file(self, path, mimetype=None): """Send a local file to the browser. This method includes the "Last-Modified", "Content-Type" and "Content-Length" headers in the response, corresponding to the file attributes. It also checks the last modification time of the local file against the "If-Modified-Since" provided by the user agent, and sends a "304 Not Modified" response if it matches. """ if not os.path.isfile(path): raise HTTPNotFound(_("File %(path)s not found", path=path)) stat = os.stat(path) mtime = datetime.fromtimestamp(stat.st_mtime, localtz) last_modified = http_date(mtime) if last_modified == self.get_header('If-Modified-Since'): self.send_response(304) self.send_header('Content-Length', 0) self.end_headers() raise RequestDone if not mimetype: mimetype = mimetypes.guess_type(path)[0] or \ 'application/octet-stream' self.send_response(200) self.send_header('Content-Type', mimetype) self.send_header('Content-Length', stat.st_size) self.send_header('Last-Modified', last_modified) use_xsendfile = getattr(self, 'use_xsendfile', False) if use_xsendfile: xsendfile_header = getattr(self, 'xsendfile_header', None) if xsendfile_header: self.send_header(xsendfile_header, os.path.abspath(path)) else: use_xsendfile = False self.end_headers() if not use_xsendfile and self.method != 'HEAD': fileobj = open(path, 'rb') file_wrapper = self.environ.get('wsgi.file_wrapper', _FileWrapper) self._response = file_wrapper(fileobj, 4096) raise RequestDone
def runTest(self): """Test timeline in RSS format.""" pagename = random_unique_camel() self._tester.create_wiki_page(pagename) page = WikiPage(self._testenv.get_trac_environment(), pagename) self._tester.go_to_timeline() code, content = tc.download_link("RSS Feed") self.assertEqual(200, code) pattern = r"""<\?xml version="1.0"\?>[\n]+ <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Functional Tests</title> <link>http://127.0.0.1:\d+/timeline</link> <description>Trac Timeline</description> <language>en-US</language> <generator>Trac [^<]+</generator> <image> <title>Functional Tests</title> <url>http://127.0.0.1:\d+/chrome/site/your_project_logo.png</url> <link>http://127.0.0.1:\d+/timeline</link> </image> <item> <title>%(pagename)s created</title> <dc:creator>admin</dc:creator> <pubDate>%(http_date)s</pubDate> <link>http://127.0.0.1:\d+/wiki/%(pagename)s\?version=1</link> <guid isPermaLink="false">http://127.0.0.1:\d+/wiki/%(pagename)s\?version=1/\d+</guid> <description>[^<]+</description> <category>wiki</category> </item> """ % { 'pagename': pagename, 'http_date': http_date(page.time) } if not re.match(pattern.encode('utf-8'), content, re.MULTILINE | re.DOTALL): url = tc.write_source(content) raise AssertionError( "Regex didn't match: {!r} not found in {}".format( pattern, url))
def export_rss(self, req, query): query.verbose = True db = self.env.get_db_cnx() results = query.execute(req, db) for result in results: result['href'] = req.abs_href.ticket(result['id']) if result['reporter'].find('@') == -1: result['reporter'] = '' if result['description']: # unicode() cancels out the Markup() returned by wiki_to_html descr = wiki_to_html(result['description'], self.env, req, db, absurls=True) result['description'] = unicode(descr) if result['time']: result['time'] = http_date(result['time']) req.hdf['query.results'] = results req.hdf['query.href'] = req.abs_href.query(group=query.group, groupdesc=query.groupdesc and 1 or None, verbose=query.verbose and 1 or None, **query.constraints) return (req.hdf.render('query_rss.cs'), 'application/rss+xml')
def grouped_changelog_entries(self, ticket, db, when=0): """Iterate on changelog entries, consolidating related changes in a `dict` object. """ changelog = ticket.get_changelog(when=when, db=db) autonum = 0 # used for "root" numbers last_uid = current = None for date, author, field, old, new, permanent in changelog: uid = date, author, permanent if uid != last_uid: if current: yield current last_uid = uid current = { 'http_date': http_date(date), 'date': format_datetime(date), 'author': author, 'fields': {}, 'permanent': permanent } if permanent and not when: autonum += 1 current['cnum'] = autonum # some common processing for fields if field == 'comment': current['comment'] = new if old: if '.' in old: # retrieve parent.child relationship parent_num, this_num = old.split('.', 1) current['replyto'] = parent_num else: this_num = old current['cnum'] = int(this_num) else: current['fields'][field] = {'old': old, 'new': new} if current: yield current
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 process_request(self, req): req.perm.assert_permission('LOG_VIEW') mode = req.args.get('mode', 'stop_on_copy') path = req.args.get('path', '/') rev = req.args.get('rev') stop_rev = req.args.get('stop_rev') format = req.args.get('format') verbose = req.args.get('verbose') limit = LOG_LIMIT repos = self.env.get_repository(req.authname) normpath = repos.normalize_path(path) rev = unicode(repos.normalize_rev(rev)) if stop_rev: stop_rev = unicode(repos.normalize_rev(stop_rev)) if repos.rev_older_than(rev, stop_rev): rev, stop_rev = stop_rev, rev req.hdf['title'] = path + ' (log)' req.hdf['log'] = { 'mode': mode, 'path': path, 'rev': rev, 'verbose': verbose, 'stop_rev': stop_rev, 'browser_href': req.href.browser(path), 'changeset_href': req.href.changeset(), 'log_href': req.href.log(path, rev=rev) } path_links = get_path_links(req.href, path, rev) req.hdf['log.path'] = path_links if path_links: add_link(req, 'up', path_links[-1]['href'], u'Répertoire parent') # The `history()` method depends on the mode: # * for ''stop on copy'' and ''follow copies'', it's `Node.history()` # * for ''show only add, delete'' it's`Repository.get_path_history()` if mode == 'path_history': def history(limit): for h in repos.get_path_history(path, rev, limit): yield h else: history = get_existing_node(req, repos, path, rev).get_history # -- retrieve history, asking for limit+1 results info = [] previous_path = repos.normalize_path(path) for old_path, old_rev, old_chg in history(limit + 1): if stop_rev and repos.rev_older_than(old_rev, stop_rev): break old_path = repos.normalize_path(old_path) item = { 'rev': str(old_rev), 'path': old_path, 'log_href': req.href.log(old_path, rev=old_rev), 'browser_href': req.href.browser(old_path, rev=old_rev), 'changeset_href': req.href.changeset(old_rev), 'restricted_href': req.href.changeset(old_rev, new_path=old_path), 'change': old_chg } if not (mode == 'path_history' and old_chg == Changeset.EDIT): info.append(item) if old_path and old_path != previous_path \ and not (mode == 'path_history' and old_path == normpath): item['copyfrom_path'] = old_path if mode == 'stop_on_copy': break if len(info) > limit: # we want limit+1 entries break previous_path = old_path if info == []: # FIXME: we should send a 404 error here raise TracError( u"Le fichier ou le répertoire '%s' n'existe pas " u"en révision %s ou pour toute révision précédente." % (path, rev), u'Chemin inexistant') def make_log_href(path, **args): link_rev = rev if rev == str(repos.youngest_rev): link_rev = None params = {'rev': link_rev, 'mode': mode, 'limit': limit} params.update(args) if verbose: params['verbose'] = verbose return req.href.log(path, **params) if len(info ) == limit + 1: # limit+1 reached, there _might_ be some more next_rev = info[-1]['rev'] next_path = info[-1]['path'] add_link( req, 'next', make_log_href(next_path, rev=next_rev), u'Journal des révisions (repartant de %s, rév. %s)' % (next_path, next_rev)) # now, only show 'limit' results del info[-1] req.hdf['log.items'] = info revs = [i['rev'] for i in info] changes = get_changes(self.env, repos, revs, verbose, req, format) if format == 'rss': # Get the email addresses of all known users email_map = {} for username, name, email in self.env.get_known_users(): if email: email_map[username] = email for cs in changes.values(): # For RSS, author must be an email address author = cs['author'] author_email = '' if '@' in author: author_email = author elif email_map.has_key(author): author_email = email_map[author] cs['author'] = author_email cs['date'] = http_date(cs['date_seconds']) elif format == 'changelog': for rev in revs: changeset = repos.get_changeset(rev) cs = changes[rev] cs['message'] = wrap(changeset.message, 70, initial_indent='\t', subsequent_indent='\t') files = [] actions = [] for path, kind, chg, bpath, brev in changeset.get_changes(): files.append(chg == Changeset.DELETE and bpath or path) actions.append(chg) cs['files'] = files cs['actions'] = actions req.hdf['log.changes'] = changes if req.args.get('format') == 'changelog': return 'log_changelog.cs', 'text/plain' elif req.args.get('format') == 'rss': return 'log_rss.cs', 'application/rss+xml' add_stylesheet(req, 'common/css/browser.css') add_stylesheet(req, 'common/css/diff.css') rss_href = make_log_href(path, format='rss', stop_rev=stop_rev) add_link(req, 'alternate', rss_href, 'RSS Feed', 'application/rss+xml', 'rss') changelog_href = make_log_href(path, format='changelog', stop_rev=stop_rev) add_link(req, 'alternate', changelog_href, 'ChangeLog', 'text/plain') return 'log.cs', None
def _render_file(self, req, context, repos, node, rev=None): req.perm(node.resource).require("FILE_VIEW") mimeview = Mimeview(self.env) # MIME type detection content = node.get_processed_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", "text/plain" if format == "txt" else mime_type) req.send_header("Last-Modified", http_date(node.last_modified)) if rev is None: req.send_header("Pragma", "no-cache") req.send_header("Cache-Control", "no-cache") req.send_header("Expires", "Fri, 01 Jan 1999 00:00:00 GMT") 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() # Note: don't pass an iterable instance to RequestDone, instead # call req.write() with each chunk here to avoid SEGVs (#11805) while chunk: req.write(chunk) chunk = content.read(CHUNK_SIZE) raise RequestDone else: # The changeset corresponding to the last change on `node` # is more interesting than the `rev` changeset. changeset = repos.get_changeset(node.created_rev) # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != "text/plain": plain_href = req.href.browser(repos.reponame or None, 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.export(rev or repos.youngest_rev, repos.reponame or None, node.path) 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, rev, mime_type) content = None # the remainder of that content is not needed add_stylesheet(req, "common/css/code.css") annotations = ["lineno"] annotate = req.args.get("annotate") if annotate: annotations.insert(0, annotate) preview_data = mimeview.preview_data( context, node.get_processed_content(), node.get_content_length(), mime_type, node.created_path, raw_href, annotations=annotations, force_source=bool(annotate), ) return {"changeset": changeset, "size": node.content_length, "preview": preview_data, "annotate": annotate}
class TimelineModule(Component): implements(INavigationContributor, IPermissionRequestor, IRequestHandler) event_providers = ExtensionPoint(ITimelineEventProvider) default_daysback = IntOption( 'timeline', 'default_daysback', 30, """Default number of days displayed in the Timeline, in days. (''since 0.9.'')""") # INavigationContributor methods def get_active_navigation_item(self, req): return 'timeline' def get_navigation_items(self, req): if not req.perm.has_permission('TIMELINE_VIEW'): return yield ('mainnav', 'timeline', html.A('Timeline', href=req.href.timeline(), accesskey=2)) # IPermissionRequestor methods def get_permission_actions(self): return ['TIMELINE_VIEW'] # IRequestHandler methods def match_request(self, req): return re.match(r'/timeline/?', req.path_info) is not None def process_request(self, req): req.perm.assert_permission('TIMELINE_VIEW') format = req.args.get('format') maxrows = int(req.args.get('max', 0)) # Parse the from date and adjust the timestamp to the last second of # the day t = time.localtime() if req.args.has_key('from'): try: t = time.strptime(req.args.get('from'), '%x') except: pass fromdate = time.mktime( (t[0], t[1], t[2], 23, 59, 59, t[6], t[7], t[8])) try: daysback = max(0, int(req.args.get('daysback', ''))) except ValueError: daysback = self.default_daysback req.hdf['timeline.from'] = format_date(fromdate) req.hdf['timeline.daysback'] = daysback available_filters = [] for event_provider in self.event_providers: available_filters += event_provider.get_timeline_filters(req) filters = [] # check the request or session for enabled filters, or use default for test in (lambda f: req.args.has_key(f[0]), lambda f: req.session.get('timeline.filter.%s' % f[0], '')\ == '1', lambda f: len(f) == 2 or f[2]): if filters: break filters = [f[0] for f in available_filters if test(f)] # save the results of submitting the timeline form to the session if req.args.has_key('update'): for filter in available_filters: key = 'timeline.filter.%s' % filter[0] if req.args.has_key(filter[0]): req.session[key] = '1' elif req.session.has_key(key): del req.session[key] stop = fromdate start = stop - (daysback + 1) * 86400 events = [] for event_provider in self.event_providers: try: events += event_provider.get_timeline_events( req, start, stop, filters) except Exception, e: # cope with a failure of that provider self._provider_failure(e, req, event_provider, filters, [f[0] for f in available_filters]) events.sort(lambda x, y: cmp(y[3], x[3])) if maxrows and len(events) > maxrows: del events[maxrows:] req.hdf['title'] = 'Timeline' # Get the email addresses of all known users email_map = {} for username, name, email in self.env.get_known_users(): if email: email_map[username] = email idx = 0 for kind, href, title, date, author, message in events: event = { 'kind': kind, 'title': title, 'href': href, 'author': author or 'anonymous', 'date': format_date(date), 'time': format_time(date, '%H:%M'), 'dateuid': int(date), 'message': message } if format == 'rss': # Strip/escape HTML markup if isinstance(title, Markup): title = title.plaintext(keeplinebreaks=False) event['title'] = title event['message'] = to_unicode(message) if author: # For RSS, author must be an email address event['author.email'] = '*****@*****.**' # if author.find('@') != -1: # event['author.email'] = author # elif email_map.has_key(author): # event['author.email'] = email_map[author] event['date'] = http_date(date) req.hdf['timeline.events.%s' % idx] = event idx += 1 if format == 'rss': return 'timeline_rss.cs', 'application/rss+xml' add_stylesheet(req, 'common/css/timeline.css') rss_href = req.href.timeline([(f, 'on') for f in filters], daysback=90, max=50, format='rss') add_link(req, 'alternate', rss_href, 'RSS Feed', 'application/rss+xml', 'rss') for idx, fltr in enumerate(available_filters): req.hdf['timeline.filters.%d' % idx] = { 'name': fltr[0], 'label': fltr[1], 'enabled': int(fltr[0] in filters) } return 'timeline.cs', None
def process_request(self, req): req.perm.assert_permission('LOG_VIEW') mode = req.args.get('mode', 'stop_on_copy') path = req.args.get('path', '/') rev = req.args.get('rev') stop_rev = req.args.get('stop_rev') format = req.args.get('format') verbose = req.args.get('verbose') limit = LOG_LIMIT repos = self.env.get_repository(req.authname) normpath = repos.normalize_path(path) rev = unicode(repos.normalize_rev(rev)) if stop_rev: stop_rev = unicode(repos.normalize_rev(stop_rev)) if repos.rev_older_than(rev, stop_rev): rev, stop_rev = stop_rev, rev req.hdf['title'] = path + ' (log)' req.hdf['log'] = { 'mode': mode, 'path': path, 'rev': rev, 'verbose': verbose, 'stop_rev': stop_rev, 'browser_href': req.href.browser(path), 'changeset_href': req.href.changeset(), 'log_href': req.href.log(path, rev=rev) } path_links = get_path_links(req.href, path, rev) req.hdf['log.path'] = path_links if path_links: add_link(req, 'up', path_links[-1]['href'], 'Parent directory') # The `history()` method depends on the mode: # * for ''stop on copy'' and ''follow copies'', it's `Node.history()` # * for ''show only add, delete'' it's`Repository.get_path_history()` if mode == 'path_history': def history(limit): for h in repos.get_path_history(path, rev, limit): yield h else: history = get_existing_node(req, repos, path, rev).get_history # -- retrieve history, asking for limit+1 results info = [] previous_path = repos.normalize_path(path) for old_path, old_rev, old_chg in history(limit+1): if stop_rev and repos.rev_older_than(old_rev, stop_rev): break old_path = repos.normalize_path(old_path) item = { 'rev': str(old_rev), 'path': old_path, 'log_href': req.href.log(old_path, rev=old_rev), 'browser_href': req.href.browser(old_path, rev=old_rev), 'changeset_href': req.href.changeset(old_rev), 'restricted_href': req.href.changeset(old_rev, new_path=old_path), 'change': old_chg } if not (mode == 'path_history' and old_chg == Changeset.EDIT): info.append(item) if old_path and old_path != previous_path \ and not (mode == 'path_history' and old_path == normpath): item['copyfrom_path'] = old_path if mode == 'stop_on_copy': break if len(info) > limit: # we want limit+1 entries break previous_path = old_path if info == []: # FIXME: we should send a 404 error here raise TracError("The file or directory '%s' doesn't exist " "at revision %s or at any previous revision." % (path, rev), 'Nonexistent path') def make_log_href(path, **args): link_rev = rev if rev == str(repos.youngest_rev): link_rev = None params = {'rev': link_rev, 'mode': mode, 'limit': limit} params.update(args) if verbose: params['verbose'] = verbose return req.href.log(path, **params) if len(info) == limit+1: # limit+1 reached, there _might_ be some more next_rev = info[-1]['rev'] next_path = info[-1]['path'] add_link(req, 'next', make_log_href(next_path, rev=next_rev), u'리비전 로그 ( %s, 리비전 %s 에서 다시 시작)' % (next_path, next_rev)) # now, only show 'limit' results del info[-1] req.hdf['log.items'] = info revs = [i['rev'] for i in info] changes = get_changes(self.env, repos, revs, verbose, req, format) if format == 'rss': # Get the email addresses of all known users email_map = {} for username,name,email in self.env.get_known_users(): if email: email_map[username] = email for cs in changes.values(): # For RSS, author must be an email address author = cs['author'] author_email = '' if '@' in author: author_email = author elif email_map.has_key(author): author_email = email_map[author] cs['author'] = author_email cs['date'] = http_date(cs['date_seconds']) elif format == 'changelog': for rev in revs: changeset = repos.get_changeset(rev) cs = changes[rev] cs['message'] = wrap(changeset.message, 70, initial_indent='\t', subsequent_indent='\t') files = [] actions = [] for path, kind, chg, bpath, brev in changeset.get_changes(): files.append(chg == Changeset.DELETE and bpath or path) actions.append(chg) cs['files'] = files cs['actions'] = actions req.hdf['log.changes'] = changes if req.args.get('format') == 'changelog': return 'log_changelog.cs', 'text/plain' elif req.args.get('format') == 'rss': return 'log_rss.cs', 'application/rss+xml' add_stylesheet(req, 'common/css/browser.css') add_stylesheet(req, 'common/css/diff.css') rss_href = make_log_href(path, format='rss', stop_rev=stop_rev) add_link(req, 'alternate', rss_href, 'RSS Feed', 'application/rss+xml', 'rss') changelog_href = make_log_href(path, format='changelog', stop_rev=stop_rev) add_link(req, 'alternate', changelog_href, 'ChangeLog', 'text/plain') return 'log.cs', None
class SimileTimelineModule(Component): implements(ITemplateProvider, IRequestHandler, INavigationContributor) # IRequestHandler methods def match_request(self, req): return req.path_info.startswith('/stimeline') def process_request(self, req): req.perm.assert_permission('TIMELINE_VIEW') format = req.args.get('format') maxrows = int(req.args.get('max', 0)) # Parse the from date and adjust the timestamp to the last second of # the day t = time.localtime() if req.args.has_key('from'): try: t = time.strptime(req.args.get('from'), '%x') except: pass fromdate = time.mktime( (t[0], t[1], t[2], 23, 59, 59, t[6], t[7], t[8])) try: daysback = max(0, int(req.args.get('daysback', ''))) except ValueError: daysback = TimelineModule(self.env).default_daysback req.hdf['timeline.from'] = format_date(fromdate) req.hdf['timeline.daysback'] = daysback available_filters = [] for event_provider in TimelineModule(self.env).event_providers: available_filters += event_provider.get_timeline_filters(req) filters = [] # check the request or session for enabled filters, or use default for test in (lambda f: req.args.has_key(f[0]), lambda f: req.session.get('timeline.filter.%s' % f[0], '')\ == '1', lambda f: len(f) == 2 or f[2]): if filters: break filters = [f[0] for f in available_filters if test(f)] # save the results of submitting the timeline form to the session if req.args.has_key('update'): for filter in available_filters: key = 'timeline.filter.%s' % filter[0] if req.args.has_key(filter[0]): req.session[key] = '1' elif req.session.has_key(key): del req.session[key] stop = fromdate start = stop - (daysback + 1) * 86400 events = [] for event_provider in TimelineModule(self.env).event_providers: try: events += event_provider.get_timeline_events( req, start, stop, filters) except Exception, e: # cope with a failure of that provider self._provider_failure(e, req, event_provider, filters, [f[0] for f in available_filters]) events.sort(lambda x, y: cmp(y[3], x[3])) if maxrows and len(events) > maxrows: del events[maxrows:] req.hdf['title'] = 'Timeline' # Get the email addresses of all known users email_map = {} for username, name, email in self.env.get_known_users(): if email: email_map[username] = email idx = 0 for kind, href, title, date, author, message in events: event = { 'kind': kind, 'title': re.sub(r'<[^>]*>', '', unicode(title)), 'href': href, 'author': author or 'anonymous', 'date': format_date(date, '%m/%d/%Y'), 'time': format_time(date, '%H:%M'), 'message': message.replace('…', '...'), 'icon': req.href.chrome('common', kind + '.png') } if format == 'rss': # Strip/escape HTML markup if isinstance(title, Markup): title = title.plaintext(keeplinebreaks=False) event['title'] = title event['message'] = to_unicode(message) if author: # For RSS, author must be an email address if author.find('@') != -1: event['author.email'] = author elif email_map.has_key(author): event['author.email'] = email_map[author] event['date'] = http_date(date) req.hdf['timeline.events.%s' % idx] = event idx += 1 if format == 'rss': return 'timeline_rss.cs', 'application/rss+xml' if format == 'xml': return 'stimeline_xml.cs', 'application/xml' add_stylesheet(req, 'common/css/timeline.css') rss_href = req.href.timeline([(f, 'on') for f in filters], daysback=90, max=50, format='rss') add_link(req, 'alternate', rss_href, 'RSS Feed', 'application/rss+xml', 'rss') for idx, fltr in enumerate(available_filters): req.hdf['timeline.filters.%d' % idx] = { 'name': fltr[0], 'label': fltr[1], 'enabled': int(fltr[0] in filters) } ## NEW LINES add_script(req, 'stimeline/js/simile/timeline-api.js') #add_abs_script(req, "http://simile.mit.edu/timeline/api/timeline-api.js") add_script(req, 'stimeline/js/simile.js') xml_args = { 'daysback': daysback, 'from': time.strftime('%x', time.localtime(fromdate)), 'format': 'xml', } xml_args.update(dict([(f, 'on') for f in filters])) xml_href = req.href.stimeline(**xml_args) req.hdf['stimeline.xml_href'] = Markup(xml_href) req.hdf['stimeline.href'] = req.href.stimeline() return 'stimeline.cs', None
if cell.find('@') != -1: value['rss'] = cell elif cell in email_map: value['rss'] = email_map[cell] elif column == 'report': value['report_href'] = req.href.report(cell) elif column in ('time', 'date', 'changetime', 'created', 'modified'): if cell == 'None': value['date'] = value['time'] = cell value['datetime'] = value['gmt'] = cell else: value['date'] = format_date(cell) value['time'] = format_time(cell) value['datetime'] = format_datetime(cell) value['gmt'] = http_date(cell) prefix = 'report.items.%d.%s' % (row_idx, unicode(column)) req.hdf[prefix] = unicode(cell) for key in value.keys(): req.hdf[prefix + '.' + key] = value[key] col_idx += 1 row_idx += 1 req.hdf['report.numrows'] = row_idx if format == 'rss': return 'report_rss.cs', 'application/rss+xml' elif format == 'csv': self._render_csv(req, cols, rows) return None elif format == 'tab':
class PygmentsRenderer(Component): """HTML renderer for syntax highlighting based on Pygments.""" implements(ISystemInfoProvider, IHTMLPreviewRenderer, IPreferencePanelProvider, IRequestHandler) default_style = Option( 'mimeviewer', 'pygments_default_style', 'trac', """The default style to use for Pygments syntax highlighting.""") pygments_modes = ListOption( 'mimeviewer', 'pygments_modes', '', doc="""List of additional MIME types known by Pygments. For each, a tuple `mimetype:mode:quality` has to be specified, where `mimetype` is the MIME type, `mode` is the corresponding Pygments mode to be used for the conversion and `quality` is the quality ratio associated to this conversion. That can also be used to override the default quality ratio used by the Pygments render.""") expand_tabs = True returns_source = True QUALITY_RATIO = 7 EXAMPLE = """<!DOCTYPE html> <html lang="en"> <head> <title>Hello, world!</title> <script> jQuery(document).ready(function($) { $("h1").fadeIn("slow"); }); </script> </head> <body> <h1>Hello, world!</h1> </body> </html>""" def __init__(self): self._types = None # ISystemInfoProvider methods def get_system_info(self): version = get_pkginfo(pygments).get('version') # if installed from source, fallback to the hardcoded version info if not version and hasattr(pygments, '__version__'): version = pygments.__version__ yield 'Pygments', version # IHTMLPreviewRenderer methods def get_extra_mimetypes(self): for lexname, aliases, _, mimetypes in get_all_lexers(): for mimetype in mimetypes: yield mimetype, aliases def get_quality_ratio(self, mimetype): # Extend default MIME type to mode mappings with configured ones if self._types is None: self._init_types() try: return self._types[mimetype][1] except KeyError: return 0 def render(self, context, mimetype, content, filename=None, rev=None): req = context.req if self._types is None: self._init_types() add_stylesheet( req, '/pygments/%s.css' % req.session.get('pygments_style', self.default_style)) try: if len(content) > 0: mimetype = mimetype.split(';', 1)[0] language = self._types[mimetype][0] return self._generate(language, content) except (KeyError, ValueError): raise Exception("No Pygments lexer found for mime-type '%s'." % mimetype) # IPreferencePanelProvider methods def get_preference_panels(self, req): yield ('pygments', _('Syntax Highlighting')) def render_preference_panel(self, req, panel): styles = list(get_all_styles()) if req.method == 'POST': style = req.args.get('style') if style and style in styles: req.session['pygments_style'] = style add_notice(req, _('Your preferences have been saved.')) req.redirect(req.href.prefs(panel or None)) output = self._generate('html', self.EXAMPLE) return 'prefs_pygments.html', { 'output': output, 'selection': req.session.get('pygments_style', self.default_style), 'styles': styles } # IRequestHandler methods def match_request(self, req): match = re.match(r'/pygments/([-\w]+)\.css', req.path_info) if match: req.args['style'] = match.group(1) return True def process_request(self, req): style = req.args['style'] try: style_cls = get_style_by_name(style) except ValueError, e: raise HTTPNotFound(e) parts = style_cls.__module__.split('.') filename = resource_filename('.'.join(parts[:-1]), parts[-1] + '.py') mtime = datetime.fromtimestamp(os.path.getmtime(filename), localtz) last_modified = http_date(mtime) if last_modified == req.get_header('If-Modified-Since'): req.send_response(304) req.end_headers() return formatter = HtmlFormatter(style=style_cls) content = u'\n\n'.join([ formatter.get_style_defs('div.code pre'), formatter.get_style_defs('table.code td') ]).encode('utf-8') req.send_response(200) req.send_header('Content-Type', 'text/css; charset=utf-8') req.send_header('Last-Modified', last_modified) req.send_header('Content-Length', len(content)) req.write(content)
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 _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 process_request(self, req): req.perm('pastebin').assert_permission('PASTEBIN_VIEW') add_stylesheet(req, 'pastebin/css/pastebin.css') add_stylesheet(req, 'common/css/code.css') if (not req.args): req.redirect(req.href.pastebin()) # new post if req.args['new_paste']: title = req.args.get('title', 'untitled') author = req.args.get('author', req.authname) mimetype = req.args.get('mimetype', 'text/plain') data = req.args.get('data', '') error = False # check if we reply to a paste if 'reply' in req.args and req.args['reply'].isdigit(): replyto = req.args['reply'] paste = Paste(self.env, id=replyto) if paste: title = paste.title if not title.startswith('Re:'): title = 'Re: ' + title data = paste.data mimetype = paste.mimetype else: replyto = '0' if 'delete' in req.args and req.args['delete'].isdigit(): req.perm('pastebin').assert_permission('PASTEBIN_DELETE') delete = req.args['delete'] paste = Paste(self.env, id=delete) if paste: paste.delete() data = { 'mode': 'delete', 'paste': paste, } return 'pastebin.html', data, None if req.method == 'POST': req.perm('pastebin').assert_permission('PASTEBIN_CREATE') if not data.strip(): error = True else: paste = Paste(self.env, title=title, author=author, mimetype=mimetype, data=data) paste.save() req.redirect(req.href.pastebin(paste.id)) data = { 'mode': 'new', 'replyto': replyto, 'mimetypes': self._get_mimetypes(), 'mimetype': mimetype, 'title': title, 'author': author, 'error': error, 'data': data, 'recent': get_pastes(env=self.env, number=self.max_recent) } # show post else: req.perm('pastebin').assert_permission('PASTEBIN_VIEW') paste = Paste(self.env, req.args['paste_id']) # text format if req.args.get('format') in ('txt', 'raw') and self.enable_other_formats: if req.args['format'] == 'txt': mimetype = 'text/plain' else: mimetype = paste.mimetype if self._download_allowed(mimetype): self.env.log.info("*** serving download") content = paste.data req.send_response(200) req.send_header('Content-Type', mimetype) req.send_header('Content-Length', len(content)) req.send_header('Last-Modified', http_date(paste.time)) req.end_headers() if isinstance(content, unicode): content = content.encode('utf-8') req.write(content) return else: self.env.log.info("*** download denied") data = { 'mode': 'show', 'paste': paste, 'highlighter': self._get_highlighter(paste.mimetype), } if self.enable_other_formats: if self._download_allowed(paste.mimetype): # add link for original format raw_href = req.href.pastebin(paste.id, format='raw') add_link(req, 'alternate', raw_href, _('Original Format'), paste.mimetype) if paste.mimetype != 'text/plain' and self._download_allowed( 'text/plain'): # add link for text format plain_href = req.href.pastebin(paste.id, format='txt') add_link(req, 'alternate', plain_href, _('Plain Text'), 'text/plain') return 'pastebin.html', data, None
def process_request(self, req): req.perm('pastebin').assert_permission('PASTEBIN_VIEW') add_stylesheet(req, 'pastebin/css/pastebin.css') add_stylesheet(req, 'common/css/code.css') if (not req.args): req.redirect(req.href.pastebin()) # new post if req.args['new_paste']: title = req.args.get('title', 'untitled') author = req.args.get('author', req.authname) mimetype = req.args.get('mimetype', 'text/plain') data = req.args.get('data', '') error = False # check if we reply to a paste if 'reply' in req.args and req.args['reply'].isdigit(): replyto = req.args['reply'] paste = Paste(self.env, id=replyto) if paste: title = paste.title if not title.startswith('Re:'): title = 'Re: ' + title data = paste.data mimetype = paste.mimetype else: replyto = '0' if 'delete' in req.args and req.args['delete'].isdigit(): req.perm('pastebin').assert_permission('PASTEBIN_DELETE') delete = req.args['delete'] paste = Paste(self.env, id=delete) if paste: paste.delete() data = { 'mode': 'delete', 'paste': paste, } return 'pastebin.html', data, None if req.method == 'POST': req.perm('pastebin').assert_permission('PASTEBIN_CREATE') if not data.strip(): error = True else: paste = Paste(self.env, title=title, author=author, mimetype=mimetype, data=data ) paste.save() req.redirect(req.href.pastebin(paste.id)) data = { 'mode': 'new', 'replyto': replyto, 'mimetypes': self._get_mimetypes(), 'mimetype': mimetype, 'title': title, 'author': author, 'error': error, 'data': data, 'recent': get_pastes(env=self.env, number=self.max_recent) } # show post else: req.perm('pastebin').assert_permission('PASTEBIN_VIEW') paste = Paste(self.env, req.args['paste_id']) # text format if req.args.get('format') in ('txt', 'raw') and self.enable_other_formats: if req.args['format'] == 'txt': mimetype = 'text/plain' else: mimetype = paste.mimetype if self._download_allowed(mimetype): self.env.log.info("*** serving download") content = paste.data req.send_response(200) req.send_header('Content-Type', mimetype) req.send_header('Content-Length', len(content)) req.send_header('Last-Modified', http_date(paste.time)) req.end_headers() if isinstance(content, unicode): content = content.encode('utf-8') req.write(content) return else: self.env.log.info("*** download denied") data = { 'mode': 'show', 'paste': paste, 'highlighter': self._get_highlighter(paste.mimetype), } if self.enable_other_formats: if self._download_allowed(paste.mimetype): # add link for original format raw_href = req.href.pastebin(paste.id, format='raw') add_link(req, 'alternate', raw_href, _('Original Format'), paste.mimetype) if paste.mimetype != 'text/plain' and self._download_allowed('text/plain'): # add link for text format plain_href = req.href.pastebin(paste.id, format='txt') add_link(req, 'alternate', plain_href, _('Plain Text'), 'text/plain') return 'pastebin.html', data, None
def render_zip(req, filename, repos, root_node, iter_nodes): """Send a ZIP file containing the data corresponding to the `nodes` iterable. :type root_node: `~trac.versioncontrol.api.Node` :param root_node: optional ancestor for all the *nodes* :param iter_nodes: callable taking the optional *root_node* as input and generating the `~trac.versioncontrol.api.Node` for which the content should be added into the zip. """ req.send_response(200) req.send_header('Content-Type', 'application/zip') req.send_header('Content-Disposition', content_disposition('inline', filename)) if root_node: req.send_header('Last-Modified', http_date(root_node.last_modified)) root_path = root_node.path.rstrip('/') else: root_path = '' if root_path: root_path += '/' root_name = root_node.name + '/' else: root_name = '' root_len = len(root_path) req.end_headers() def write_partial(fileobj, start): end = fileobj.tell() fileobj.seek(start, 0) remaining = end - start while remaining > 0: chunk = fileobj.read(min(remaining, 4096)) req.write(chunk) remaining -= len(chunk) fileobj.seek(end, 0) return end pos = 0 with TemporaryFile(prefix='trac-', suffix='.zip') as fileobj: with ZipFile(fileobj, 'w', ZIP_DEFLATED) as zipfile: for node in iter_nodes(root_node): if node is root_node: continue path = node.path.strip('/') assert path.startswith(root_path) path = root_name + path[root_len:] kwargs = {'mtime': node.last_modified} data = None if node.isfile: with content_closing( node.get_processed_content(eol_hint='CRLF')) \ as content: data = content.read() props = node.get_properties() # Subversion specific if 'svn:special' in props and data.startswith('link '): data = data[5:] kwargs['symlink'] = True if 'svn:executable' in props: kwargs['executable'] = True elif node.isdir and path: kwargs['dir'] = True data = '' if data is not None: zipfile.writestr(create_zipinfo(path, **kwargs), data) pos = write_partial(fileobj, pos) write_partial(fileobj, pos) raise RequestDone
elif column == 'reporter': if cell.find('@') != -1: value['rss'] = cell elif cell in email_map: value['rss'] = email_map[cell] elif column == 'report': value['report_href'] = req.href.report(cell) elif column in ('time', 'date','changetime', 'created', 'modified'): if cell == 'None': value['date'] = value['time'] = cell value['datetime'] = value['gmt'] = cell else: value['date'] = format_date(cell) value['time'] = format_time(cell) value['datetime'] = format_datetime(cell) value['gmt'] = http_date(cell) prefix = 'report.items.%d.%s' % (row_idx, unicode(column)) req.hdf[prefix] = unicode(cell) for key in value.keys(): req.hdf[prefix + '.' + key] = value[key] col_idx += 1 row_idx += 1 req.hdf['report.numrows'] = row_idx if format == 'rss': return 'report_rss.cs', 'application/rss+xml' elif format == 'csv': filename = id and 'report_%s.csv' % id or 'report.csv' self._render_csv(req, cols, rows, mimetype='text/csv', filename=filename)
def _render_file(self, req, context, repos, node, rev=None): req.perm(node.resource).require('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', 'text/plain' if format == 'txt' else mime_type) req.send_header('Content-Length', node.content_length) req.send_header('Last-Modified', http_date(node.last_modified)) if rev is None: req.send_header('Pragma', 'no-cache') req.send_header('Cache-Control', 'no-cache') req.send_header('Expires', 'Fri, 01 Jan 1999 00:00:00 GMT') 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.created_rev) # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != 'text/plain': plain_href = req.href.browser(repos.reponame or None, 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.export(rev or repos.youngest_rev, repos.reponame or None, node.path) 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 add_stylesheet(req, 'common/css/code.css') annotations = ['lineno'] annotate = req.args.get('annotate') if annotate: annotations.insert(0, annotate) preview_data = mimeview.preview_data(context, node.get_content(), node.get_content_length(), mime_type, node.created_path, raw_href, annotations=annotations, force_source=bool(annotate)) return { 'changeset': changeset, 'size': node.content_length, 'preview': preview_data, 'annotate': annotate, }
def process_request(self, req): req.perm.assert_permission("LOG_VIEW") mode = req.args.get("mode", "stop_on_copy") path = req.args.get("path", "/") rev = req.args.get("rev") stop_rev = req.args.get("stop_rev") format = req.args.get("format") verbose = req.args.get("verbose") limit = LOG_LIMIT repos = self.env.get_repository(req.authname) normpath = repos.normalize_path(path) rev = unicode(repos.normalize_rev(rev)) if stop_rev: stop_rev = unicode(repos.normalize_rev(stop_rev)) if repos.rev_older_than(rev, stop_rev): rev, stop_rev = stop_rev, rev req.hdf["title"] = path + " (log)" req.hdf["log"] = { "mode": mode, "path": path, "rev": rev, "verbose": verbose, "stop_rev": stop_rev, "browser_href": req.href.browser(path), "changeset_href": req.href.changeset(), "log_href": req.href.log(path, rev=rev), } path_links = get_path_links(req.href, path, rev) req.hdf["log.path"] = path_links if path_links: add_link(req, "up", path_links[-1]["href"], u"Répertoire parent") # The `history()` method depends on the mode: # * for ''stop on copy'' and ''follow copies'', it's `Node.history()` # * for ''show only add, delete'' it's`Repository.get_path_history()` if mode == "path_history": def history(limit): for h in repos.get_path_history(path, rev, limit): yield h else: history = get_existing_node(req, repos, path, rev).get_history # -- retrieve history, asking for limit+1 results info = [] previous_path = repos.normalize_path(path) for old_path, old_rev, old_chg in history(limit + 1): if stop_rev and repos.rev_older_than(old_rev, stop_rev): break old_path = repos.normalize_path(old_path) item = { "rev": str(old_rev), "path": old_path, "log_href": req.href.log(old_path, rev=old_rev), "browser_href": req.href.browser(old_path, rev=old_rev), "changeset_href": req.href.changeset(old_rev), "restricted_href": req.href.changeset(old_rev, new_path=old_path), "change": old_chg, } if not (mode == "path_history" and old_chg == Changeset.EDIT): info.append(item) if old_path and old_path != previous_path and not (mode == "path_history" and old_path == normpath): item["copyfrom_path"] = old_path if mode == "stop_on_copy": break if len(info) > limit: # we want limit+1 entries break previous_path = old_path if info == []: # FIXME: we should send a 404 error here raise TracError( u"Le fichier ou le répertoire '%s' n'existe pas " u"en révision %s ou pour toute révision précédente." % (path, rev), u"Chemin inexistant", ) def make_log_href(path, **args): link_rev = rev if rev == str(repos.youngest_rev): link_rev = None params = {"rev": link_rev, "mode": mode, "limit": limit} params.update(args) if verbose: params["verbose"] = verbose return req.href.log(path, **params) if len(info) == limit + 1: # limit+1 reached, there _might_ be some more next_rev = info[-1]["rev"] next_path = info[-1]["path"] add_link( req, "next", make_log_href(next_path, rev=next_rev), u"Journal des révisions (repartant de %s, rév. %s)" % (next_path, next_rev), ) # now, only show 'limit' results del info[-1] req.hdf["log.items"] = info revs = [i["rev"] for i in info] changes = get_changes(self.env, repos, revs, verbose, req, format) if format == "rss": # Get the email addresses of all known users email_map = {} for username, name, email in self.env.get_known_users(): if email: email_map[username] = email for cs in changes.values(): # For RSS, author must be an email address author = cs["author"] author_email = "" if "@" in author: author_email = author elif email_map.has_key(author): author_email = email_map[author] cs["author"] = author_email cs["date"] = http_date(cs["date_seconds"]) elif format == "changelog": for rev in revs: changeset = repos.get_changeset(rev) cs = changes[rev] cs["message"] = wrap(changeset.message, 70, initial_indent="\t", subsequent_indent="\t") files = [] actions = [] for path, kind, chg, bpath, brev in changeset.get_changes(): files.append(chg == Changeset.DELETE and bpath or path) actions.append(chg) cs["files"] = files cs["actions"] = actions req.hdf["log.changes"] = changes if req.args.get("format") == "changelog": return "log_changelog.cs", "text/plain" elif req.args.get("format") == "rss": return "log_rss.cs", "application/rss+xml" add_stylesheet(req, "common/css/browser.css") add_stylesheet(req, "common/css/diff.css") rss_href = make_log_href(path, format="rss", stop_rev=stop_rev) add_link(req, "alternate", rss_href, "RSS Feed", "application/rss+xml", "rss") changelog_href = make_log_href(path, format="changelog", stop_rev=stop_rev) add_link(req, "alternate", changelog_href, "ChangeLog", "text/plain") return "log.cs", None