Beispiel #1
0
    def convert_content(self, req, input_type, text, output_type):
        page_name = req.args.get('page', 'WikiStart')
        wikipage = WikiPage(self.env, page_name)
        
        wikiprint = WikiPrint(self.env)
        
        page = wikiprint.wikipage_to_html(text, page_name, req)
        
        #Get page title from first header in outline
        out = StringIO.StringIO()
        context = Context(Resource('wiki', page_name), req.abs_href, req.perm)
        context.req = req

        outline = OutlineFormatter(self.env, context)
        outline.format(text, out, 1, 1)
        
        title = wikipage.name
        for depth, anchor, text in outline.outline:
            if depth == 1:
                title = text
                break
        
        out = wikiprint.html_to_pdf(req, [page], book = (output_type == 'pdfbook'),
            title=title,
            subject="%s - %s" % (self.env.project_name, page_name),
            version=str(wikipage.version),
            date=format_datetime(to_datetime(None)))
        return (out, 'application/pdf')
    def get_project_events(self, project, days, minutes):
        """ List all events in project that happened in a given time span.
        """
        events = []
        project_href = Href(conf.url_projects_path + "/" + project.env_name)

        req = DummyReq('user', 'password', 'method', 'uri', 'args')
        req.permissions = (
        'TICKET_VIEW', 'CHANGESET_VIEW', 'WIKI_VIEW', 'ATTACHMENT_VIEW', 'DISCUSSION_VIEW', 'MILESTONE_VIEW')
        req.authname = 'authname'
        req.abs_href = project_href

        project_env = open_environment(conf.getEnvironmentSysPath(project.env_name), use_cache=True)
        event_provider = ProjectTimelineEvents(project_env)
        last_events = event_provider.get_timeline_events(req,
            time_in_days=days,
            time_in_minutes=minutes)

        for event in last_events:
            context = Context(resource=Resource(), href=project_href)
            context.req = req
            context.perm = req.perm
            events.append([project, event, context])

        events.sort(lambda x, y: cmp(y[1]['date'], x[1]['date']))
        return events
Beispiel #3
0
def email_default_context():
    class NoEmailViewPerm(MockPerm):
        def has_permission(self, action, realm_or_resource=None, id=False, version=False):
            return action != "EMAIL_VIEW"

        __contains__ = has_permission

    context = Context(Resource("wiki", "WikiStart"), href=Href("/"), perm=NoEmailViewPerm())
    context.req = None  # 0.12 FIXME .req shouldn't be required by formatter
    return context
Beispiel #4
0
    def wikipage_to_html(self, text, page_name, req):
        """
        Converts a wiki text to HTML, and makes some replacements in order to fix
        internal and external links and references
        """

        self.env.log.debug('WikiPrint => Start function wikipage_to_html')

        #Remove exclude expressions
        for r in EXCLUDE_RES:
            text = r.sub('', text)
        
        #Escape [[PageOutline]], to avoid wiki processing
        for r in [re.compile(r'\[\[TOC(\(.*\))?\]\]'), re.compile(r'\[\[PageOutline(\(.*\))?\]\]')]:
            text = r.sub('![[pdf-toc]]', text)
            
        for macro in self.omit_macros:
            r = re.compile(r'\[\[' + macro + r'\(.*?\]\]')
            text = r.sub('', text)
            r = re.compile(r'^\{\{\{\r?\n#!' + macro + r'\r?\n(^.*\r?\n)*?^\}\}\}', re.MULTILINE)
            text = r.sub('', text)

        link_format = req.args.get('link_format', None)
            
        if self.omit_links:
            r1 = re.compile(r'\[wiki:(.*?) (.*?)\]')
            text = r1.sub('[\g<2>]', text)            
            r2 = re.compile(r'\[wiki:(.*?)\]')
            text = r2.sub('[\g<1>]', text)            
        elif link_format:
            #Keep links to the same export format
            r = re.compile(r'(?<=\[wiki:)(.*?)(?=(?: .*?)?\])')
            text = r.sub('\g<1>?format=%s&link_format=%s' % (link_format, link_format), text)
            
        if self.rebase_links:
            r = re.compile(r'\[wiki:(.*?)\]')
            text = r.sub('[%s/wiki/\g<1>]' % self.rebase_links, text)

        self.env.log.debug('WikiPrint => Wiki input for WikiPrint: %r' % text)
        
        #First create a Context object from the wiki page
        context = Context(Resource('wiki', page_name), req.abs_href, req.perm)
        context.req = req
        
        #Now convert in that context
        page = format_to_html(self.env, context, text)
        self.env.log.debug('WikiPrint => Wiki to HTML output: %r' % page)
        
        self.env.log.debug('WikiPrint => HTML output for WikiPrint is: %r' % page)
        self.env.log.debug('WikiPrint => Finish function wikipage_to_html')

        return page
def get_list_pages(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    artifact_id = request.req.args.get('artifact', None)
    if artifact_id is None:
        raise Exception("No artifact was specified.")
    dbp.load_artifact(artifact_id)
    artifact = dbp.pool.get_item(artifact_id)

    results = []
    for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(artifact):
        page = WikiPage(dbp.env, pagename)

        results.append(
            {'href': get_resource_url(dbp.env, page.resource, request.req.href),
             'title': pagename,
             'date': user_time(request.req, format_datetime, page.time),
             'author': page.author,
             'excerpt': shorten_result(page.text)}
        )

    data = {
        'context': Context.from_request(request.req, resource),
        'artifact': artifact,
        'results': results,
    }
    return 'list_pages.html', data, None
 def template_data(self, req, query, kwargs=None):
     db = self.env.get_read_db()
     tickets = query.execute(req, db)
     filtered_tickets = [ticket for ticket in tickets if 'TICKET_VIEW' in req.perm(Ticket(self.env, int(ticket['id'])).resource)]
     context = Context.from_request(req, 'query')
     return query.template_data(context, filtered_tickets, None,
                                datetime.now(req.tz), req)
Beispiel #7
0
 def _handle_builder(self, req):
     m = self.BUILDER_RE.match(req.path_info)
     try:
         builder = m.group(1) or None
     except Exception as e:
         builder = None
     master = BuildBotSystem(self.buildbot_url)
     if builder is None:
         data = {'names': master.getAllBuilders()}
         return 'bbw_allbuilders.html', data, 'text/html'
     else:
         class Foo:
             pass
         b = Foo()
         b.name = str(builder)
         b.current = 'CURRENT-TEXT'
         b.recent = []
         b.slaves = []
         data = {'builder': b}
         try:
             master = BuildBotSystem(self.buildbot_url)
             data = {'builder': master.getBuilder(builder)}
         except Exception as e:
             print('Error fetching builder stats', e)
         data['context'] = Context.from_request(req, ('buildbot', builder))
         return 'bbw_builder.html', data, 'text/html'
def get_edit_artifact(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env, operation="MODIFY")

    assert(isinstance(obj, Instance)) # otherwise, we're trying to edit something that is not an artifact

    aa_attributes = [name for name, val in obj.get_values()]
    attr_suggestions = [attr.name for attr in obj.get_attributes() if not attr.name in aa_attributes]

    values = []
    for name,val in obj.get_values():
        if type(val) is list:
            for v in val:
                values.append((str(uuid.uuid4()), name, v))
        else:
            values.append((str(uuid.uuid4()), name, val))

    # track access
    dbp.track_it("artifact", obj.get_id(), "edit", request.req.authname, str(datetime.now()))

    data = {
        'context': Context.from_request(request.req, resource),
        'spec_name': obj.__class__.get_name() if not obj.__class__ == Instance else "",
        'artifact': obj,
        'artifact_values': values,
        'attr_suggestions' : attr_suggestions,
        'default': obj.str_attr,
        'url_path': request.req.href.customartifacts('artifact', obj.get_id()),
        }
    return 'edit_artifact_%s.html' % (request.get_format(),), data, None
Beispiel #9
0
 def process_request(self, req):
     # Allow all POST requests (with a valid __FORM_TOKEN, ensuring that
     # the client has at least some permission). Additionally, allow GET
     # requests from TRAC_ADMIN for testing purposes.
     if req.method != 'POST':
         req.perm.require('TRAC_ADMIN')
         
     # @todo: Embed "tips" within the rendered output for the editor
     # (recognize TracLinks, table-stuff, macros, processors)
     # @todo: Save the content in server-side user-specific field for recovery
     
     realm = req.args.get('realm', 'wiki')
     id = req.args.get('id')
     version = req.args.get('version')
     if version is not None:
         try:
             version = int(version)
         except ValueError:
             version = None
     text = req.args.get('text', '')
     flavor = req.args.get('flavor')
     options = {}
     if 'escape_newlines' in req.args:
         options['escape_newlines'] = bool(int(req.args['escape_newlines']
                                               or 0))
     if 'shorten' in req.args:
         options['shorten'] = bool(int(req.args['shorten'] or 0))
     
     resource = Resource(realm, id=id, version=version)
     context = Context.from_request(req, resource)
     rendered = format_to(self.env, flavor, context, text, **options)
     req.send(rendered.encode('utf-8'))
Beispiel #10
0
    def _convert_query(self, req, query, sheet_query=True,
                       sheet_history=False):
        # no paginator
        query.max = 0
        query.has_more_pages = False
        query.offset = 0

        # extract all fields except custom fields
        cols = ['id']
        cols.extend(f['name'] for f in query.fields if not f.get('custom'))
        cols.extend(name for name in ('time', 'changetime')
                         if name not in cols)
        query.cols = cols

        if hasattr(self.env, 'get_read_db'):
            db = self.env.get_read_db()
        else:
            db = self.env.get_db_cnx()
        tickets = query.execute(req, db)
        # add custom fields to avoid error to join many tables
        custom_fields = [f['name'] for f in query.fields if f.get('custom')]
        self._fill_custom_fields(tickets, custom_fields, db)

        context = Context.from_request(req, 'query', absurls=True)
        cols.extend([name for name in custom_fields if name not in cols])
        data = query.template_data(context, tickets)

        book = Workbook(encoding='utf-8', style_compression=1)
        if sheet_query:
            self._create_sheet_query(req, context, data, book)
        if sheet_history:
            self._create_sheet_history(req, context, data, book)
        return get_workbook_content(book), 'application/vnd.ms-excel'
    def expand_macro(self, formatter, name, content):
        # Example: [[ASA(42)]]
        args, kw = parse_args(content)
        args = [arg.strip() for arg in args]
        if not args or not args[0].isdigit():
            raise TracError('Custom artifact id not specified')
        args, kw = parse_args(content)
        if not args or not args[0].isdigit():
            raise TracError('Custom artifact id not specified')
        artifact_id = int(args[0])
        dbp = DBPool(self.env, InstancePool())
        try:
            dbp.load_artifact(id=artifact_id)
        except ValueError:
            return system_message("Custom Artifact not found", "No custom artifact was found for id '{0}'.".format(artifact_id))
        artifact = dbp.pool.get_item(id=artifact_id)
        artifact_url = formatter.req.href.customartifacts('artifact/{0}'.format(artifact.get_id()))
        res = Core._get_resource(artifact) if not artifact in (Entity, Instance, None) and not type(artifact)==unicode else None
        spec_name, spec_url, values = _get_artifact_details(artifact, formatter.req)

        tpl='view_artifact_dialog.html'
        data = {
            'context': Context.from_request(formatter.req, res),
            'spec_name': spec_name,
            'spec_url': spec_url,
            'artifact': artifact,
            'artifact_url': artifact_url,
            'artifacts_values': values,
        }
        return Chrome(self.env).render_template(formatter.req, tpl, data, None, fragment=True)
Beispiel #12
0
 def _do_ticket(self, req, template, data, content_type):
     if 'ticket' in data and 'linked_tickets' in data:
         ticket = data['ticket']
         context = Context.from_request(req, ticket.resource)
         
         # Add name:#n links to link fields of Ticket instance when
         # flowing from storage to browser
         if req.method == 'GET':
             RemoteLinksProvider(self.env).augment_ticket(ticket)
         
         # Rerender link fields
         for field in data['fields']:
             if field['type'] == 'link':
                 name = field['name']
                 field['rendered'] = format_to_oneliner(self.env, context,
                                                        ticket[name])
         
         # Add RemoteTicket objects for linked issues table, and pass list
         # of rejects that could not be retrieved
         linked_tickets, linked_rejects = self._remote_tickets(ticket,
                                                               context)
         data['linked_tickets'].extend(linked_tickets)
         data['linked_rejects'].extend(linked_rejects)
     
     # Provide list of remote sites if newlinked form options are present
     if 'newlinked_options' in data:
         remote_sites = RemoteTicketSystem(self.env).get_remote_tracs()
         data['remote_sites'] = remote_sites
     
     return (template, data, content_type)
Beispiel #13
0
    def pre_process_request(self, req, handler):
        if req.path_info.startswith('/wiki'):
            if req.method == 'POST' and req.args.get('action','view') == 'view':
                post_handler = None
                for poster in self.macro_posters:
                    if not hasattr(poster, 'match_macro_post'): continue
                    rv = poster.match_macro_post(req)
                    if isinstance(rv, (str, unicode)):
                        rv = rv in req.args.keys()
                    if rv:
                        post_handler = poster
                        break
                if post_handler:
                    post_handler.process_macro_post(req)
                else:
                    # Silly stuff here
                    self.log.debug('MacroPostModule: Unclaimed POST, scanning page %s', req.path_info[6:])
                    page = WikiPage(self.env, req.path_info[6:])
                    matches = self.macro_re.findall(page.text) + self.proc_re.findall(page.text)
                    for name in matches:
                        self.log.debug('MacroPostModule: Found macro "%s"', name)
                        resource = Resource('wiki', name)
                        context = Context.from_request(req, resource)
                        wp = WikiProcessor(Formatter(self.env, context), name)
                        if wp.macro_provider is None:
                            self.log.debug('MacroPostModule: Invalid name!!! How did that happen')
                            continue
                        if hasattr(wp.macro_provider, 'process_macro_post') and \
                           not hasattr(wp.macro_provider, 'match_macro_post'):
                            wp.macro_provider.process_macro_post(req)
                req.environ['REQUEST_METHOD'] = 'GET' # Revert back to a GET

        return handler
Beispiel #14
0
    def wiki_to_html(self, wikitext, req):
        self.env.log.debug('start function wiki_to_html') # pylint: disable-msg=E1101

        # Remove some macros (TOC is better handled in ODT itself)
        for macro in self.remove_macros:
            wikitext = re.sub('\[\[%s(\([^)]*\))?\]\]' % macro, "", wikitext)

        # Now convert wiki to HTML
        out = StringIO()
        context = Context.from_request(req, absurls=True)
        Formatter(self.env, # pylint: disable-msg=E1101
                  context('wiki', self.page_name)).format(wikitext, out)
        html = Markup(out.getvalue())
        html = html.encode("utf-8", 'replace')

        # Clean up the HTML
        html = re.sub('<span class="icon">.</span>', '', html) # Remove external link icon
        tidy_options = dict(output_xhtml=1, add_xml_decl=1, indent=1,
                            tidy_mark=0, input_encoding='utf8',
                            output_encoding='utf8', doctype='auto',
                            wrap=0, char_encoding='utf8')
        html = tidy.parseString(html, **tidy_options)
        # Replace nbsp with entity:
        # http://www.mail-archive.com/[email protected]/msg03670.html
        html = str(html).replace("&nbsp;", "&#160;")
        # Tidy creates newlines after <pre> (by indenting)
        html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html)
        return html
Beispiel #15
0
 def process_request(self, req):
     # Allow all POST requests (with a valid __FORM_TOKEN, ensuring that
     # the client has at least some permission). Additionally, allow GET
     # requests from TRAC_ADMIN for testing purposes.
     if req.method != 'POST':
         req.perm.require('TRAC_ADMIN')
     realm = req.args.get('realm', 'wiki')
     id = req.args.get('id')
     version = req.args.get('version')
     if version is not None:
         try:
             version = int(version)
         except ValueError:
             version = None
     text = req.args.get('text', '')
     flavor = req.args.get('flavor')
     options = {}
     if 'escape_newlines' in req.args:
         options['escape_newlines'] = bool(int(req.args['escape_newlines']
                                               or 0))
     if 'shorten' in req.args:
         options['shorten'] = bool(int(req.args['shorten'] or 0))
     
     resource = Resource(realm, id=id, version=version)
     context = Context.from_request(req, resource)
     rendered = format_to(self.env, flavor, context, text, **options)
     req.send(rendered.encode('utf-8'))
Beispiel #16
0
 def process_request(self, req):
     page_name = req.args.get('page_name', '')
     if page_name == '':
         page_name = 'index'
     
     # Add breadcrumb
     package_name, filename = self._get_package_and_filename(page_name)
     index_file = filename[:-len('.txt')] + '/index.txt'
     
     if not self._resource_exists(package_name, filename):
         # check if it is a folder, then match with index
         if self._resource_exists(package_name, index_file):
             filename = index_file
         else:
             error_msg = _('Page %(page_name)s not found', page_name=page_name)
             raise ResourceNotFound(error_msg)
     
     utf8_string = resource_string(package_name, filename)
     help_contents = utf8_string.decode('UTF-8')
     # add navigation bar
     self._set_prev_next(req)
     
     data = dict(context=Context.from_request(req), contents=help_contents,
                 page_name=page_name)
     return ('agilo_help.html', data, 'text/html')
Beispiel #17
0
    def refresh_project(self, project_identifier, from_date, to_date=datetime.now(datefmt.localtz),
                        afilters=None, update=False):
        """
        Will refresh a project events in cache in given date range.

        .. NOTE::

            Dates needs to be given in datefmt.localtz form

        """
        # Initialize objects
        project = Project.get(env_name=project_identifier)
        if not project:
            conf.log.warning('Project {0} is already removed from system or it cannot be found'.format(project_identifier))
            return

        e = open_environment(conf.getEnvironmentSysPath(project.env_name), use_cache=True)
        pte = ProjectTimelineEvents(e)
        providers = pte.event_providers

        project_href = Href(conf.url_projects_path + '/' + project.env_name)

        context = Context(resource=Resource(), href=project_href)
        req = self._create_dummy_req(project_identifier)
        context.req = req
        context.perm = req.perm

        # Read events from timeline
        events = []
        for provider in providers:
            try:
                # Use filters in parameter or check filters from providers
                if afilters:
                    filters = afilters
                else:
                    available_filters = provider.get_timeline_filters(req) or []
                    filters = [f[0] for f in available_filters]

                for event in provider.get_timeline_events(req, from_date, to_date, filters):
                    event_data = self._event_data(provider, event)
                    if event_data['author'] != 'trac': # Skip system events
                        events.append(CachedEvent.from_event_data(project, event_data, context, filters[0]))
            except:
                conf.log.error("Could not read timeline events for %s from %s" % (project_identifier, str(provider)))

        # Write events into sql table
        self._write_events_into_cache(events, update)
Beispiel #18
0
 def _get_welcome_page(self, req):
     rendered_page = None
     wiki_welcome = WikiPage(self.env, 'WelcomePage')
     if wiki_welcome:
         context = Context.from_request(req, wiki_welcome.resource)
         wiki_renderer = WikiTextRenderer(self.env)
         rendered_page = wiki_renderer.render(context, 'text/x-trac-wiki', wiki_welcome.text)
     return rendered_page
Beispiel #19
0
    def setup_widget(self, widgetns):
      r"""(Insert | update) the IWidgetProvider in the global 
      namespace.

      @param widgetns             widget name.
      @throws RuntimeError        if a widget with requested name cannot 
                                  be found.
      """
      globs = self.globalns
      globs['ctx'] = Context.from_request(globs['req'])
      globs['auth_ctx'] = Context.from_request(globs['auth_req'])
      for wp in self.dbsys.providers :
        if widgetns in set(wp.get_widgets()) :
          globs['widget'] = wp
          break
      else :
        raise InvalidIdentifier('Cannot load widget provider for %s' % widgetns)
Beispiel #20
0
 def setUp(self):
     """ Set up the testing environment. """
     self.env = EnvironmentStub(enable=[CodeExample])
     self.req = Mock(base_path='', chrome={}, args={},
                     abs_href=Href('/'), href=Href('/'),
                     session={}, perm=[], authname=None,
                     tz=None, locale='utf-8')
     self.context = Context.from_request(self.req)
Beispiel #21
0
    def get_html(self, req):
        """
        Get the raw content from the repository and convert to html.
        """
        mime_type, chunk = self.get_raw()
        if not mime_type.startswith('text'):
            raise TracError("Invalid mime-type: %s" % mime_type)

        # Hack to support images, we change the path from relative
        # the document being requested to absolute.
        # 1: Ignore http and ftp urls to allow images to be fetched
        # 2: Assume URLS beginning with "/" are relative to top-level
        # 3: Assume URLS that do not include "http/ftp" are relative to
        #    current path.
        def fixup(m):
            text = m.group(1)
            if text.startswith('http:') or text.startswith('ftp:'):
                return m.group(0)
            if text.startswith('/'):
                text = text[1:]
            dir = self.dir
            if dir.endswith('/'):
                dir = dir[:-1] 
            return '.. image:: %s/%s' % (req.href.docs(dir), text)
        chunk = re.sub('\.\. image\:\:\s*(\S+)', fixup, chunk, re.MULTILINE)

        # Assume all wiki pages are ReStructuredText documents 
        result = self.mimeview.render(Context.from_request(req), mime_type, chunk)

        if not isinstance(result, (str, unicode)):
            result = unicode(result)

        # Hack to pretty-print source code (assumes all literal-blocks 
        # contain source code).
        result = result.replace('<pre class="literal-block">',
                                '<pre class="literal-block prettyprint">')

        if 'prettyprint' in result:
            # FIXME: Add as an event listener instead?
            result += """
                <script type="text/javascript">
                var origOnLoad = window.onload;
                function onLoad() {
                    if (origOnLoad) {
                      if(typeof(origOnLoad) == "string") {
                        eval(origOnLoad);
                      }
                      else {
                        origOnLoad();
                      }
                    } 
                    prettyPrint();
                }
                window.onload = onLoad;
                </script>
            """

        return Markup(result)
Beispiel #22
0
    def render_admin_panel(self, req, cat, page, path_info):
        """
        Returns the admin view and handles the form actions
        """
        req.perm.require('TRAC_ADMIN')

        project = Project.get(self.env)

        if req.method == 'POST':
            myprojects_url = conf.url_home_path + "/myprojects"
            conf.log.exception("Redirect URL: %s" % myprojects_url)
            thisurl = Href(req.base_path)(req.path_info)
            context = Context.from_request(req)

            # Handle project remove
            if 'remove' in req.args:
                # Don't allow removing home
                if project.env_name == conf.sys_home_project_name:
                    add_warning(req, 'Cannot remove home project')
                    return req.redirect(thisurl)

                # Archive the project before removal
                archive = ProjectArchive()
                archived = archive.archive(project)

                if not archived:
                    add_warning(req, 'Could not archive project "%s". Will not remove the project' % project.project_name)
                    return req.redirect(thisurl)

                # Notify listeners. The project object still exists, but database does not
                for listener in self.project_change_listeners:
                    listener.project_archived(project)

                # Do the actual project removal
                projects = Projects()
                if projects.remove_project(project):
                    # Notify listeners. The project object still exists, but database does not
                    for listener in self.project_change_listeners:
                        listener.project_deleted(project)

                    # NOTE: We no longer have project tables/session etc available
                    req.redirect(myprojects_url)

                else:
                    add_warning(req, 'Could not remove project "%s". Try again later' % project.project_name)
                    return req.redirect(thisurl)

        add_script(req, 'multiproject/js/jquery-ui.js')
        add_script(req, 'multiproject/js/multiproject.js')
        add_script(req, 'multiproject/js/admin_system.js')
        add_stylesheet(req, 'multiproject/css/jquery-ui.css')

        # NOTE: Trac automatically puts 'project' dict in chrome thus it cannot be used
        data = {'multiproject': {
            'project':project,
            'home_url':conf.url_home_path
        }}
        return 'admin_system.html', data
Beispiel #23
0
    def process_request(self, req):
        """ Process request for listing, creating and removing projects
        """
        add_script(req, 'multiproject/js/summary.js')
        data = {}

        if req.authname == 'anonymous':
            req.perm.require('PROJECT_VIEW')


        if not ('PROJECT_VIEW' in req.perm or 'PROJECT_PRIVATE_VIEW' in req.perm):
            return 'no_access.html', data, None

        # Load project from db
        project = Project.get(self.env)

        if req.args.get('action') == 'timeline_events':
            return self.get_summary_timeline_events(req, project.created)

        # TODO: Move project timeline implementation into macro
        # Get recent timeline events
        
        # TODO: Move project downloads implementation into macro
        # Get list of featured downloads
        downloads = []
        if self.env.is_component_enabled('tracdownloads.api.DownloadsApi'):
            api = None

            # In case of import error we don't have it, so don't return any downloads
            try:
                from tracdownloads.api import DownloadsApi
                api = DownloadsApi(self.env)
            except ImportError:
                self.log.warning("Unable to import DownloadsApi, but it's enabled.")

            if api:
                downloads = api.get_summary_items()

        # Load wiki:SummaryPage and show it as a main page
        summary_content = None
        summary_wiki = WikiPage(self.env, 'SummaryPage')
        if summary_wiki:
            context = Context.from_request(req, summary_wiki.resource)
            wiki_renderer = WikiTextRenderer(self.env)
            summary_content = wiki_renderer.render(context, 'text/x-trac-wiki', summary_wiki.text)

        
        data = {
            '_project_': project, # project object of a project we are in
            'downloads': downloads, # list of featured downloads
            'wiki_summary': summary_content, # Rendered content of the SummaryPage
            'is_summary': True,
            'env': self.env,
        }

        return 'summary.html', data, None
Beispiel #24
0
 def setUp(self):
     env = EnvironmentStub(enable=[Chrome, PatchRenderer])
     req = Mock(base_path='', chrome={}, args={}, session={},
                abs_href=Href('/'), href=Href('/'),
                perm=MockPerm(), authname=None, tz=None)
     self.context = Context.from_request(req)
     self.patch = Mimeview(env).renderers[0]
     patch_html = open(os.path.join(os.path.split(__file__)[0],
                                    'patch.html'))
     self.patch_html = Stream(list(HTMLParser(patch_html)))
Beispiel #25
0
 def setUp(self):
     self.env = EnvironmentStub(enable=[Chrome, PygmentsRenderer])
     self.pygments = Mimeview(self.env).renderers[0]
     self.req = Mock(base_path='', chrome={}, args={},
                     abs_href=Href('/'), href=Href('/'),
                     session={}, perm=None, authname=None, tz=None)
     self.context = Context.from_request(self.req)
     pygments_html = open(os.path.join(os.path.split(__file__)[0],
                                    'pygments.html'))
     self.pygments_html = Stream(list(HTMLParser(pygments_html)))
Beispiel #26
0
 def _export_ticket(self, req, ticket, writer, field_names):
     
     cols = [unicode(ticket.id)]
     for name in field_names:
         value = ticket[name] or ''
         if name in ('cc', 'reporter'):
             context = Context.from_request(req, ticket.resource)
             value = Chrome(self.env).format_emails(context, value, ' ')
         cols.append(unicode(value).encode('utf-8'))
     writer.writerow(cols)
Beispiel #27
0
    def process_request(self, req):
        req.perm.require('BROWSER_VIEW')

        presel = req.args.get('preselected')
        if presel and (presel + '/').startswith(req.href.browser() + '/'):
            req.redirect(presel)

        path = req.args.get('path', '/')
        rev = req.args.get('rev', '')
        if rev in ('', 'HEAD'):
            rev = None
        order = req.args.get('order', 'name').lower()
        desc = req.args.has_key('desc')
        xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest'
        
        rm = RepositoryManager(self.env)
        all_repositories = rm.get_all_repositories()
        reponame, repos, path = rm.get_repository_by_path(path)

        # Repository index
        show_index = not reponame and path == '/'
        if show_index:
            if repos and (as_bool(all_repositories[''].get('hidden'))
                          or not repos.can_view(req.perm)):
                repos = None

        if not repos and reponame:
            raise ResourceNotFound(_("Repository '%(repo)s' not found",
                                     repo=reponame))

        if reponame and reponame != repos.reponame: # Redirect alias
            qs = req.query_string
            req.redirect(req.href.browser(repos.reponame or None, path)
                         + (qs and '?' + qs or ''))
        reponame = repos and repos.reponame or None
        
        # Find node for the requested path/rev
        context = Context.from_request(req)
        node = None
        display_rev = lambda rev: rev
        if repos:
            try:
                if rev:
                    rev = repos.normalize_rev(rev)
                # If `rev` is `None`, we'll try to reuse `None` consistently,
                # as a special shortcut to the latest revision.
                rev_or_latest = rev or repos.youngest_rev
                node = get_existing_node(req, repos, path, rev_or_latest)
            except NoSuchChangeset, e:
                raise ResourceNotFound(e.message,
                                       _('Invalid changeset number'))

            context = context(repos.resource.child('source', path,
                                                   version=rev_or_latest))
            display_rev = repos.display_rev
Beispiel #28
0
 def post_process_request(self, req, template, data, content_type):
     if template == 'report_view.html' and req.args.get('id'):
         format = req.args.get('format')
         if format == 'xls':
             resource = Resource('report', req.args['id'])
             data['context'] = Context.from_request(req, resource,
                                                    absurls=True)
             self._convert_report(req, data)
         elif not format:
             self._add_alternate_links(req)
     return template, data, content_type
def get_view_spec(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    # track access
    dbp.track_it("spec", obj.get_id(), "view", request.req.authname, str(datetime.now()))

    data = {
        'context': Context.from_request(request.req, resource),
        'spec': obj,
        'artifacts_url': request.req.href.customartifacts(spec=obj.get_name()),
    }
    return 'view_spec_page.html', data, None
Beispiel #30
0
	def process_request(self, req):
		req.perm.assert_permission('TICKET_VIEW')

		if 'id' in req.args.keys():
			try:
				ticket = int(req.args.get('id'))
			except ValueError:
				raise TracError('Need integer ticket id.')

			sql = ("SELECT 1 FROM ticket WHERE id=%s" %ticket)
		
			db = self.env.get_db_cnx()
			cursor = db.cursor()
			cursor.execute(sql)
			row = cursor.fetchone()
			if not row:
				raise TracError('Cannot build dependency graph for non-existent ticket %d.' % ticket)

			depth  = -1
			for key in req.args.keys():
				if key == 'depth':
					depth = req.args[key]

			options = '%s,%s' %(ticket, depth)
			add_ctxtnav(req, 'Back to Ticket #%s'%ticket,
							req.href.ticket(ticket))
			title = 'Ticket #%s Dependency Graph' %ticket
			headline = 'Dependency Graph for Ticket #%s' %ticket
		else:
			constraints = {}
			for key in req.args.keys():
				if isinstance(req.args[key], (list, tuple)):
					constraints[key] = '|'.join(req.args[key])
				else:
					constraints[key] = req.args[key]
			options = 'query:' + '&'.join(key + '=' +
						constraints[key] for key in constraints)

			title = 'Ticket query Dependency Graph'
			headline = 'Dependency Graph for Query'
			add_ctxtnav(req, 'Back to query', req.href('query', **req.args))
		
		data = {}

		context = Context.from_request(req, '')
		formatter = Formatter(self.env, context)
		graph = DepGraphMacro(self.env).expand_macro(formatter,
					'DepGraph', options)
		data['title'] = title
		data['headline'] = headline
		data['depgraph'] = Markup(graph)

		return 'depgraph.html', data, None
Beispiel #31
0
 def process_request(self, req):
     # Allow all POST requests (with a valid __FORM_TOKEN, ensuring that
     # the client has at least some permission). Additionally, allow GET
     # requests from TRAC_ADMIN for testing purposes.
     if req.method != 'POST':
         req.perm.require('TRAC_ADMIN')
         
     # @todo: Embed "tips" within the rendered output for the editor
     # (recognize TracLinks, table-stuff, macros, processors)
     # @todo: Save the content in server-side user-specific field for recovery
     
     realm = req.args.get('realm', 'wiki')
     id = req.args.get('id')
     version = req.args.get('version')
     if version is not None:
         try:
             version = int(version)
         except ValueError:
             version = None
     text = req.args.get('text', '')
     flavor = req.args.get('flavor')
     options = {}
     if 'escape_newlines' in req.args:
         options['escape_newlines'] = bool(int(req.args['escape_newlines']
                                               or 0))
     if 'shorten' in req.args:
         options['shorten'] = bool(int(req.args['shorten'] or 0))
     
     resource = Resource(realm, id=id, version=version)
     context = Context.from_request(req, resource)
     rendered = format_to_cke_html(self.env, context, text, self.code_styles, **options)
     
     # since Trac renders underlined text as `<span class="underlined">text</span>
     # instead of u-tag, we need to adjust it for compatibility's sake
     # see also discussion at Google Groups:
     # https://groups.google.com/group/trac-dev/browse_thread/thread/833206a932d1f918
     html = HTML(rendered)
     html |= Transformer('//span[@class="underline"]').rename('u').attr('class', None)
     # CKEditor renders indentation by using p style="margin-left: 40px" 
     # instead of blockquote-tag
     html |= Transformer('//blockquote/p').attr('style', 'margin-left: 40px')
     html |= Transformer('//blockquote').unwrap()
     buffer = StringIO()
     html.render(out=buffer, encoding='utf-8')
     req.send( buffer.getvalue() )
     
Beispiel #32
0
    def _wiki_view(self, req, stream):
        add_stylesheet(req, 'tags/css/tractags.css')
        tags = self._page_tags(req)
        if not tags:
            return stream
        li = []
        for tag_ in tags:
            resource = Resource('tag', tag_)
            anchor = render_resource_link(self.env,
                Context.from_request(req, resource), resource)
            anchor = anchor(rel='tag')
            li.append(tag.li(anchor, ' '))

        # TRANSLATOR: Header label text for tag list at wiki page bottom.
        insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li)
        return stream | (Transformer('//div[contains(@class,"wikipage")]')
                         .after(insert))
Beispiel #33
0
def new_csv_export(self, req, query, sep=',', mimetype='text/plain'):
    self.log.debug(
        "T&E plugin has overridden QueryModule.csv_export so to enforce field permissions"
    )

    ## find the columns that should be hidden
    hidden_fields = []
    fields = self.config.getlist(csection, 'fields', [])
    self.log.debug('QueryModule.csv_export: found : %s' % fields)
    for field in fields:
        perms = self.config.getlist(csection, '%s.permission' % field, [])
        #self.log.debug('QueryModule.csv_export: read permission config: %s has %s' % (field, perms))
        for (perm, denial) in [s.split(":") for s in perms]:
            perm = perm.upper()
            #self.log.debug('QueryModule.csv_export: testing permission: %s:%s should act= %s' %
            #               (field, perm, (not req.perm.has_permission(perm) or perm == "ALWAYS")))
            if (not req.perm.has_permission(perm) or perm
                    == "ALWAYS") and denial.lower() in ["remove", "hide"]:
                hidden_fields.append(field)
    ## END find the columns that should be hidden

    content = StringIO()
    cols = query.get_columns()
    writer = csv.writer(content, delimiter=sep)
    writer = csv.writer(content, delimiter=sep, quoting=csv.QUOTE_MINIMAL)
    writer.writerow(
        [unicode(c).encode('utf-8') for c in cols if c not in hidden_fields])

    context = Context.from_request(req)
    results = query.execute(req, self.env.get_db_cnx())
    self.log.debug('QueryModule.csv_export: hidding columns %s' %
                   hidden_fields)
    for result in results:
        ticket = Resource('ticket', result['id'])
        if 'TICKET_VIEW' in req.perm(ticket):
            values = []
            for col in cols:
                if col not in hidden_fields:
                    value = result[col]
                    if col in ('cc', 'reporter'):
                        value = Chrome(self.env).format_emails(
                            context(ticket), value)
                    values.append(unicode(value).encode('utf-8'))
            writer.writerow(values)
    return (content.getvalue(), '%s;charset=utf-8' % mimetype)
Beispiel #34
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename != 'ticket.html' and (filename != 'typedticket.html'):
            return stream
        ticket = data['ticket']
        id = ticket.id
        try:
            int(id)
            isint = 1
        except:
            isint = 0

        if isint == 1:
            content = "[[TicketBackLinks(%d)]]" % ticket.id
            content = WikiTextRenderer(self.env).render(
                Context.from_request(req), 'text/x-trac-wiki', content)
            stream |= Transformer("//div[@class='description']").after(
                tag.div(content, **{'class': "description"}))

        return stream
def get_edit_artifact(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env, operation="MODIFY")

    assert (
        isinstance(obj, Instance)
    )  # otherwise, we're trying to edit something that is not an artifact

    aa_attributes = [name for name, val in obj.get_values()]
    attr_suggestions = [
        attr.name for attr in obj.get_attributes()
        if not attr.name in aa_attributes
    ]

    values = []
    for name, val in obj.get_values():
        if type(val) is list:
            for v in val:
                values.append((str(uuid.uuid4()), name, v))
        else:
            values.append((str(uuid.uuid4()), name, val))

    # track access
    dbp.track_it("artifact", obj.get_id(), "edit", request.req.authname,
                 str(datetime.now()))

    data = {
        'context':
        Context.from_request(request.req, resource),
        'spec_name':
        obj.__class__.get_name() if not obj.__class__ == Instance else "",
        'artifact':
        obj,
        'artifact_values':
        values,
        'attr_suggestions':
        attr_suggestions,
        'default':
        obj.str_attr,
        'url_path':
        request.req.href.customartifacts('artifact', obj.get_id()),
    }
    return 'edit_artifact_%s.html' % (request.get_format(), ), data, None
Beispiel #36
0
    def process_request(self, req):
        path = req.path_info[len("/watchlist/manual"):].strip('/')
        if path.startswith('attachments'):
            return self.handle_attachment(req, path)

        language = path
        if not language:
            language = req.session.get('language', 'en-US')

        # Try to find a suitable language if no manual exists
        # in the requested one.
        if language not in self.manuals:
            # Try to find a main language,
            # e.g. 'xy' instead of 'xy-ZV'
            l = language.split('-')[0]
            language = 'en-US'  # fallback if no other is found
            if l in self.manuals:
                language = l
            else:
                # Prefer 'en-US' before any other English dialect
                if l == 'en' and 'en-US' in self.manuals:
                    language = 'en-US'
                else:
                    # If there is none try to find
                    # any other 'xy-*' language
                    l += '-'
                    for lang in sorted(self.manuals.keys()):
                        if lang.startswith(l):
                            language = lang
                            break
            req.redirect(req.href.watchlist('manual', language))

        try:
            f = open(self.manuals[language], 'r')
            text = to_unicode(f.read())
        except Exception as e:
            raise HTTPNotFound(e)

        wldict = dict(format_text=lambda text: format_to_html(
            self.env, Context.from_request(req), text),
                      text=text)
        return ("watchlist_manual.html", wldict, "text/html")
Beispiel #37
0
 def process_request(self, req):
     """Initially this will render static widgets. With time it will be 
     more and more dynamic and flexible.
     """
     if self.env[QueryModule] is not None:
         add_ctxtnav(req, _('Custom Query'), req.href.query())
     if self.env[ReportModule] is not None:
         add_ctxtnav(req, _('Reports'), req.href.report())
     template, layout_data = self.expand_layout_data(req, 
         'bootstrap_grid', self.DASHBOARD_SCHEMA)
     widgets = self.expand_widget_data(req, layout_data) 
     return template, {
                 'context' : Context.from_request(req),
                 'layout' : layout_data,
                 'widgets' : widgets,
                 'title' : _(self.mainnav_label),
                 'default' : {
                         'height' : self.default_widget_height or None
                     }
             }, None
def get_new_artifact(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env, operation="CREATE")

    assert (
        obj is Instance or isinstance(obj, Entity)
    )  # otherwise, we're trying to instantiate something that is not an artifact

    attr_suggestions = [attr.name for attr in obj.get_attributes()]

    # track access
    dbp.track_it("artifact", obj.get_id(), "new", request.req.authname,
                 str(datetime.now()))

    data = {
        'context': Context.from_request(request.req, resource),
        'spec_name': obj.get_name() if not obj == Instance else "",
        'attr_suggestions': attr_suggestions,
        'url_path': request.req.href.customartifacts('artifact'),
    }
    return 'edit_artifact_%s.html' % (request.get_format(), ), data, None
Beispiel #39
0
    def pre_process_request(self, req, handler):
        if req.path_info.startswith('/wiki'):
            if req.method == 'POST' and req.args.get('action',
                                                     'view') == 'view':
                post_handler = None
                for poster in self.macro_posters:
                    if not hasattr(poster, 'match_macro_post'): continue
                    rv = poster.match_macro_post(req)
                    if isinstance(rv, (str, unicode)):
                        rv = rv in req.args.keys()
                    if rv:
                        post_handler = poster
                        break
                if post_handler:
                    post_handler.process_macro_post(req)
                else:
                    # Silly stuff here
                    self.log.debug(
                        'MacroPostModule: Unclaimed POST, scanning page %s',
                        req.path_info[6:])
                    page = WikiPage(self.env, req.path_info[6:])
                    matches = self.macro_re.findall(
                        page.text) + self.proc_re.findall(page.text)
                    for name in matches:
                        self.log.debug('MacroPostModule: Found macro "%s"',
                                       name)
                        resource = Resource('wiki', name)
                        context = Context.from_request(req, resource)
                        wp = WikiProcessor(Formatter(self.env, context), name)
                        if wp.macro_provider is None:
                            self.log.debug(
                                'MacroPostModule: Invalid name!!! How did that happen'
                            )
                            continue
                        if hasattr(wp.macro_provider, 'process_macro_post') and \
                           not hasattr(wp.macro_provider, 'match_macro_post'):
                            wp.macro_provider.process_macro_post(req)
                req.environ['REQUEST_METHOD'] = 'GET'  # Revert back to a GET

        return handler
Beispiel #40
0
    def _check_redirect(self, req):
        """Checks if the request should be redirected."""
        if req.path_info == '/' or req.path_info == '/wiki':
            wiki = 'WikiStart'
        elif not req.path_info.startswith('/wiki/'):
            return False
        else:
            wiki = req.path_info[6:]

        wp = WikiPage(self.env, wiki, req.args.get('version'))

        if not wp.exists:
            return False

        # Check for redirect "macro":
        m = MACRO.match(wp.text)
        if not m:
            return False
        wikitarget = m.groups()[0]
        self.redirect_target = extract_url(self.env, Context.from_request(req),
                                           wikitarget)
        if not self.redirect_target:
            self.redirect_target = req.href.wiki(wikitarget)
        return True
Beispiel #41
0
 def expand_widget_data(self, req, schema):
     """Expand raw widget data and format it for use in template
     """
     # TODO: Implement dynamic dashboard specification
     widgets_spec = schema.get('widgets', {})
     widgets_index = dict([wnm, wp] \
             for wp in DashboardSystem(self.env).widget_providers \
             for wnm in wp.get_widgets()
         )
     self.log.debug("Bloodhound: Widget index %s" % (widgets_index,))
     ctx = Context.from_request(req)
     for w in widgets_spec.itervalues():
         w['c'] = widgets_index.get(w['args'][0])
         w['args'][1] = ctx
     self.log.debug("Bloodhound: Widget specs %s" % (widgets_spec,))
     chrome = Chrome(self.env)
     render = chrome.render_template
     data_strm = ( (k, w, self._render_widget(w['c'], *w['args'])) \
             for k,w in widgets_spec.iteritems())
     return dict([k, {'title' : data['title'], 
             'content' : render(wctx.req, template, data['data'], fragment=True),
             'ctxtnav' : w.get('ctxtnav', True) and data.get('ctxtnav') or None, 
             'altlinks' : w.get('altlinks', True) and data.get('altlinks') or None}] \
             for k, w, (template, data, wctx) in data_strm)
Beispiel #42
0
    def _convert_query(self,
                       req,
                       query,
                       sheet_query=True,
                       sheet_history=False):
        # no paginator
        query.max = 0
        query.has_more_pages = False
        query.offset = 0

        # extract all fields except custom fields
        cols = ['id']
        cols.extend(f['name'] for f in query.fields if not f.get('custom'))
        cols.extend(name for name in ('time', 'changetime')
                    if name not in cols)
        query.cols = cols

        if hasattr(self.env, 'get_read_db'):
            db = self.env.get_read_db()
        else:
            db = self.env.get_db_cnx()
        tickets = query.execute(req, db)
        # add custom fields to avoid error to join many tables
        custom_fields = [f['name'] for f in query.fields if f.get('custom')]
        self._fill_custom_fields(tickets, custom_fields, db)

        context = Context.from_request(req, 'query', absurls=True)
        cols.extend([name for name in custom_fields if name not in cols])
        data = query.template_data(context, tickets)

        book = Workbook(encoding='utf-8', style_compression=1)
        if sheet_query:
            self._create_sheet_query(req, context, data, book)
        if sheet_history:
            self._create_sheet_history(req, context, data, book)
        return get_workbook_content(book), 'application/vnd.ms-excel'
def get_edit_spec(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env, operation="MODIFY")

    assert (obj is Instance or isinstance(obj, Entity))

    # track access
    dbp.track_it("spec", obj.get_id(), "edit", request.req.authname,
                 str(datetime.now()))

    data = {
        'context':
        Context.from_request(request.req, resource),
        'spec':
        obj,
        'attributes':
        [(str(uuid.uuid4()), attr.name, attr.owner_spec,
          attr.get_type_readable(), attr.get_multiplicity_readable())
         for attr in obj.get_attributes()],
        'types': ['Text', 'Number'],  # , 'Adaptive Artifact'
        'multiplicities': ['1', '0..*', '1..*'],
        'url_path':
        request.req.href.customartifacts('spec', obj.get_name()),
    }
    return 'edit_spec_page.html', data, None
Beispiel #44
0
    def wiki_to_html(self, wikitext, req):
        self.env.log.debug(
            'start function wiki_to_html')  # pylint: disable-msg=E1101

        # Remove some macros (TOC is better handled in ODT itself)
        for macro in self.remove_macros:
            wikitext = re.sub('\[\[%s(\([^)]*\))?\]\]' % macro, "", wikitext)

        # Now convert wiki to HTML
        out = StringIO()
        context = Context.from_request(req, absurls=True)
        Formatter(
            self.env,  # pylint: disable-msg=E1101
            context('wiki', self.page_name)).format(wikitext, out)
        html = Markup(out.getvalue())
        html = html.encode("utf-8", 'replace')

        # Clean up the HTML
        html = re.sub('<span class="icon">.</span>', '',
                      html)  # Remove external link icon
        tidy_options = dict(output_xhtml=1,
                            add_xml_decl=1,
                            indent=1,
                            tidy_mark=0,
                            input_encoding='utf8',
                            output_encoding='utf8',
                            doctype='auto',
                            wrap=0,
                            char_encoding='utf8')
        html = tidy.parseString(html, **tidy_options)
        # Replace nbsp with entity:
        # http://www.mail-archive.com/[email protected]/msg03670.html
        html = str(html).replace("&nbsp;", "&#160;")
        # Tidy creates newlines after <pre> (by indenting)
        html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html)
        return html
Beispiel #45
0
                    if len(v) == 1:
                        args[k] = v[0]
                except TypeError:
                    pass
            args.update({'page': page, 'max': maxrows})

            qrymdl = self.env[QueryModule]
            if qrymdl is None:
                raise TracError('Query module not available (disabled?)')
            data = qrymdl.process_request(fakereq)[1]
        except TracError, exc:
            if data is not None:
                exc.title = data.get('title', 'TracQuery')
            raise
        else:
            qryctx = Context.from_request(fakereq)
            query = data['query']
            idxs = count()
            headers = [dict(title=h['label'], col=h['name'], hidden=False,
                            asc=h['name'] == query.order and not query.desc) \
                                for h in data['headers']]
            data.update(
                dict(header_groups=[headers],
                    numrows=len(data['tickets']),
                    row_groups=[(group_value,
                            [{
                                '__color__' : t['priority_value'],
                                '__idx__' : idxs.next(),
                                'cell_groups' : [[
                                        {
                                            'header' : h,
Beispiel #46
0
    def display_html(self, req, query):
        """returns the HTML according to a query for /hours view"""
        db = self.env.get_db_cnx()

        # The most recent query is stored in the user session;
        orig_list = None
        orig_time = datetime.now(utc)
        query_time = int(req.session.get('query_time', 0))
        query_time = datetime.fromtimestamp(query_time, utc)
        query_constraints = unicode(query.constraints)
        if query_constraints != req.session.get('query_constraints') \
                or query_time < orig_time - timedelta(hours=1):
            tickets = query.execute(req, db)
            # New or outdated query, (re-)initialize session vars
            req.session['query_constraints'] = query_constraints
            req.session['query_tickets'] = ' '.join(
                [str(t['id']) for t in tickets])
        else:
            orig_list = [
                int(id) for id in req.session.get('query_tickets', '').split()
            ]
            tickets = query.execute(req, db, orig_list)
            orig_time = query_time

        context = Context.from_request(req, 'query')
        ticket_data = query.template_data(context, tickets, orig_list,
                                          orig_time, req)

        # For clients without JavaScript, we add a new constraint here if
        # requested
        constraints = ticket_data['clauses'][0]
        if 'add' in req.args:
            field = req.args.get('add_filter')
            if field:
                constraint = constraints.setdefault(field, {})
                constraint.setdefault('values', []).append('')
                # FIXME: '' not always correct (e.g. checkboxes)

        req.session['query_href'] = query.get_href(context.href)
        req.session['query_time'] = to_timestamp(orig_time)
        req.session['query_tickets'] = ' '.join(
            [str(t['id']) for t in tickets])

        # data dictionary for genshi
        data = {}

        # get data for saved queries
        query_id = req.args.get('query_id')
        if query_id:
            try:
                query_id = int(query_id)
            except ValueError:
                add_warning(
                    req,
                    "query_id should be an integer, you put '%s'" % query_id)
                query_id = None
        if query_id:
            data['query_id'] = query_id
            query_data = self.get_query(query_id)

            data['query_title'] = query_data['title']
            data['query_description'] = query_data['description']

        data.setdefault('report', None)
        data.setdefault('description', None)

        data['all_columns'] = query.get_all_columns() + self.get_columns()
        # Don't allow the user to remove the id column
        data['all_columns'].remove('id')
        data['all_textareas'] = query.get_all_textareas()

        # need to re-get the cols because query will remove our fields
        cols = req.args.get('col')
        if isinstance(cols, basestring):
            cols = [cols]
        if not cols:
            cols = query.get_columns() + self.get_default_columns()
        data['col'] = cols

        now = datetime.now()
        # get the date range for the query
        if 'from_year' in req.args:
            from_date = get_date(req.args['from_year'],
                                 req.args.get('from_month'),
                                 req.args.get('from_day'))

        else:
            from_date = datetime(now.year, now.month, now.day)
            from_date = from_date - timedelta(days=7)  # 1 week ago, by default

        if 'to_year' in req.args:
            to_date = get_date(req.args['to_year'],
                               req.args.get('to_month'),
                               req.args.get('to_day'),
                               end_of_day=True)
        else:
            to_date = now

        data['prev_week'] = from_date - timedelta(days=7)
        data['months'] = list(enumerate(calendar.month_name))
        data['years'] = range(now.year, now.year - 10, -1)
        data['days'] = range(1, 32)
        data['users'] = get_all_users(self.env)
        data['cur_worker_filter'] = req.args.get('worker_filter', '*any')

        data['from_date'] = from_date
        data['to_date'] = to_date

        ticket_ids = [t['id'] for t in tickets]

        # generate data for ticket_times
        time_records = self.get_ticket_hours(
            ticket_ids,
            from_date=from_date,
            to_date=to_date,
            worker_filter=data['cur_worker_filter'])

        data['query'] = ticket_data['query']
        data['context'] = ticket_data['context']
        data['row'] = ticket_data['row']
        if 'comments' in req.args.get('row', []):
            data['row'].append('comments')
        data['constraints'] = ticket_data['clauses']

        our_labels = dict([(f['name'], f['label']) for f in self.fields])
        labels = TicketSystem(self.env).get_ticket_field_labels()
        labels.update(our_labels)
        data['labels'] = labels

        order = req.args.get('order')
        desc = bool(req.args.get('desc'))
        data['order'] = order
        data['desc'] = desc

        headers = [{
            'name':
            col,
            'label':
            labels.get(col),
            'href':
            self.get_href(query,
                          req.args,
                          context.href,
                          order=col,
                          desc=(col == order and not desc))
        } for col in cols]

        data['headers'] = headers

        data['fields'] = ticket_data['fields']
        data['modes'] = ticket_data['modes']

        # group time records
        time_records_by_ticket = {}
        for record in time_records:
            id = record['ticket']
            if id not in time_records_by_ticket:
                time_records_by_ticket[id] = []

            time_records_by_ticket[id].append(record)

        data['extra_group_fields'] = dict(ticket=dict(name='ticket',
                                                      type='select',
                                                      label='Ticket'),
                                          worker=dict(name='worker',
                                                      type='select',
                                                      label='Worker'))

        num_items = 0
        data['groups'] = []

        # merge ticket data into ticket_time records
        for key, tickets in ticket_data['groups']:
            ticket_times = []
            total_time = 0
            total_estimated_time = 0
            for ticket in tickets:
                records = time_records_by_ticket.get(ticket['id'], [])
                [rec.update(ticket) for rec in records]
                ticket_times += records

            # sort ticket_times, if needed
            if order in our_labels:
                ticket_times.sort(key=lambda x: x[order], reverse=desc)
            data['groups'].append((key, ticket_times))
            num_items += len(ticket_times)

        data['double_count_warning'] = ''

        # group by ticket id or other time_ticket fields if necessary
        if req.args.get('group') in data['extra_group_fields']:
            query.group = req.args.get('group')
            if not query.group == "id":
                data[
                    'double_count_warning'] = "Warning: estimated hours may be counted more than once if a ticket appears in multiple groups"

            tickets = data['groups'][0][1]
            groups = {}
            for time_rec in tickets:
                key = time_rec[query.group]
                if not key in groups:
                    groups[key] = []
                groups[key].append(time_rec)
            data['groups'] = sorted(groups.items())

        total_times = dict(
            (k, self.format_hours(sum(rec['seconds_worked'] for rec in v)))
            for k, v in data['groups'])
        total_estimated_times = {}
        for key, records in data['groups']:
            seen_tickets = set()
            est = 0
            for record in records:
                # do not double-count tickets
                id = record['ticket']
                if id in seen_tickets:
                    continue
                seen_tickets.add(id)
                estimatedhours = record.get('estimatedhours') or 0
                try:
                    estimatedhours = float(estimatedhours)
                except ValueError:
                    estimatedhours = 0
                est += estimatedhours * 3600
            total_estimated_times[key] = self.format_hours(est)

        data['total_times'] = total_times
        data['total_estimated_times'] = total_estimated_times

        # format records
        for record in time_records:
            if 'seconds_worked' in record:
                record['seconds_worked'] = self.format_hours(
                    record['seconds_worked'])  # XXX misleading name
            if 'time_started' in record:
                record['time_started'] = self.format_date(
                    record['time_started'])
            if 'time_submitted' in record:
                record['time_submitted'] = self.format_date(
                    record['time_submitted'])

        data['query'].num_items = num_items
        data['labels'] = TicketSystem(self.env).get_ticket_field_labels()
        data['labels'].update(labels)
        data['can_add_hours'] = req.perm.has_permission('TICKET_ADD_HOURS')

        data['multiproject'] = self.env.is_component_enabled(MultiprojectHours)

        from web_ui import TracUserHours
        data['user_hours'] = self.env.is_component_enabled(TracUserHours)

        # return the rss, if requested
        if req.args.get('format') == 'rss':
            return self.queryhours2rss(req, data)

        # return the csv, if requested
        if req.args.get('format') == 'csv':
            self.queryhours2csv(req, data)

        # add rss link
        rss_href = req.href(req.path_info, format='rss')
        add_link(req, 'alternate', rss_href, _('RSS Feed'),
                 'application/rss+xml', 'rss')

        # add csv link
        add_link(req, 'alternate',
                 req.href(req.path_info, format='csv', **req.args), 'CSV',
                 'text/csv', 'csv')

        # add navigation of weeks
        prev_args = dict(req.args)
        next_args = dict(req.args)

        prev_args['from_year'] = (from_date - timedelta(days=7)).year
        prev_args['from_month'] = (from_date - timedelta(days=7)).month
        prev_args['from_day'] = (from_date - timedelta(days=7)).day
        prev_args['to_year'] = from_date.year
        prev_args['to_month'] = from_date.month
        prev_args['to_day'] = from_date.day

        next_args['from_year'] = to_date.year
        next_args['from_month'] = to_date.month
        next_args['from_day'] = to_date.day
        next_args['to_year'] = (to_date + timedelta(days=7)).year
        next_args['to_month'] = (to_date + timedelta(days=7)).month
        next_args['to_day'] = (to_date + timedelta(days=7)).day

        add_link(req, 'prev', self.get_href(query, prev_args, context.href),
                 _('Prev Week'))
        add_link(req, 'next', self.get_href(query, next_args, context.href),
                 _('Next Week'))
        prevnext_nav(req, _('Prev Week'), _('Next Week'))

        add_ctxtnav(req, 'Cross-Project Hours', req.href.hours('multiproject'))
        add_ctxtnav(
            req, 'Hours by User',
            req.href.hours('user',
                           from_day=from_date.day,
                           from_month=from_date.month,
                           from_year=from_date.year,
                           to_day=to_date.year,
                           to_month=to_date.month,
                           to_year=to_date.year))
        add_ctxtnav(req, 'Saved Queries', req.href.hours('query/list'))

        add_stylesheet(req, 'common/css/report.css')
        add_script(req, 'common/js/query.js')

        return ('hours_timeline.html', data, 'text/html')
Beispiel #47
0
    def expand_macro(self, formatter, name, text, args=None):

        assert text.isdigit(), "Argument must be a number"

        out = "<dl class='lastevents'>"
        add_stylesheet(formatter.req, 'tracprojectmanager/css/lastevents.css')

        all_events = []
        if hasattr(self.env, 'cached_lastevents'):
            expiration = self.env.cached_lastevents[1] + timedelta(
                seconds=EVENT_CACHE_INTERVAL)
            if datetime.now() < expiration:
                all_events = self.env.cached_lastevents[0]

        if not all_events:
            stop = datetime.now(formatter.req.tz)
            start = stop - timedelta(days=EVENT_MAX_DAYS)

            projects = get_project_list(self.env, formatter.req)
            user = formatter.req.authname

            for project, project_path, project_url, env in projects:
                env_timeline = TimelineModule(env)
                for provider in env_timeline.event_providers:
                    filters = [
                        x[0]
                        for x in provider.get_timeline_filters(formatter.req)
                    ]
                    self.env.log.info("Project %s - Filters: %s", project,
                                      filters)
                    try:
                        events = provider.get_timeline_events(
                            formatter.req, start, stop, filters)
                        #self.env.log.info("Event count: %d", len([x for x in events]))

                        for event in events:
                            context = Context(formatter.resource,
                                              Href(project_url),
                                              formatter.req.perm)
                            context.req = formatter.req
                            #context = Context.from_request(formatter.req)

                            if len(event) == 6:  # 0.10 events
                                kind, url, title, date, author, desc = event
                            else:  # 0.11 events
                                if len(event) == 5:  # with special provider
                                    kind, date, author, data, provider = event
                                else:
                                    kind, date, author, data = event

                                title = to_unicode(
                                    provider.render_timeline_event(
                                        context, 'title', event))
                                url = provider.render_timeline_event(
                                    context, 'url', event)
                                desc = to_unicode(
                                    provider.render_timeline_event(
                                        context, 'description', event))

                            all_events.append((project, kind, date, title, url,
                                               author, desc))
                    except Exception, ex:
                        #import sys
                        self.env.log.warning("Exception: %s" %
                                             traceback.format_exc())
                        #out = out + "%s<br/>" % traceback.format_exc()

            all_events.sort(cmp=lambda x, y: x[2] < y[2] and 1 or -1)
            self.env.cached_lastevents = [all_events, datetime.now()]
Beispiel #48
0
class IncludeMacro(WikiMacroBase):
    """A macro to include other resources in wiki pages.
    More documentation to follow.
    """
    
    implements(IPermissionRequestor)
    
    # Default output formats for sources that need them
    default_formats = {
        'wiki': 'text/x-trac-wiki',
    }
    
    # IWikiMacroProvider methods
    def expand_macro(self, formatter, name, content):
        req = formatter.req   # Shortcut.
        safe_content = False  # Whether or not to disable cleaning HTML.
        args = [x.strip() for x in content.split(',')]
        if len(args) == 1:
            args.append(None)
        elif len(args) == 3:
            return system_message('args == %s' % args)
            if not args[2].startswith('fragment='):
                msg = ('If three arguments are given, the last one must'
                       ' start with fragment=, but tag content was %s')
                return system_message(msg % content)
        elif len(args) != 2:
            return system_message('Invalid arguments "%s"'%content)

        # Parse out fragment name.
        fragment_name = None
        if args[-1] and args[-1].startswith('fragment='):
            fragment_name = args[-1][len('fragment='):]
            args.pop()
        if len(args) == 1:
            args.append(None)
            
        # Pull out the arguments
        source, dest_format = args
        try:
            source_format, source_obj = source.split(':', 1)
        except ValueError: # If no : is present, assume its a wiki page
            source_format, source_obj = 'wiki', source
            
        # Apply a default format if needed
        if dest_format is None:
            try:
                dest_format = self.default_formats[source_format]
            except KeyError:
                pass
        
        if source_format in ('http', 'https', 'ftp'):
            # Since I can't really do recursion checking, and because this 
            # could be a source of abuse allow selectively blocking it.
            # RFE: Allow blacklist/whitelist patterns for URLS. <NPK>
            # RFE: Track page edits and prevent unauthorized users from ever entering a URL include. <NPK>
            if not req.perm.has_permission('INCLUDE_URL'):
                self.log.info('IncludeMacro: Blocking attempt by %s to include URL %s on page %s', req.authname, source, req.path_info)
                return ''
            try:
                urlf = urllib2.urlopen(source)
                out = urlf.read()  
            except urllib2.URLError, e:
                return system_message('Error while retrieving file', str(e))
            except TracError, e:
                return system_message('Error while previewing', str(e))
            ctxt = Context.from_request(req)
Beispiel #49
0
    def get_list(self, realm, wl, req, fields=None):
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        context = Context.from_request(req)
        locale = getattr(req, 'locale', LC_TIME)

        ticketlist = []
        extradict = {}
        if not fields:
            fields = set(self.default_fields['ticket'])
        else:
            fields = set(fields)

        if 'changetime' in fields:
            max_changetime = datetime(1970, 1, 1, tzinfo=utc)
            min_changetime = datetime.now(utc)
        if 'time' in fields:
            max_time = datetime(1970, 1, 1, tzinfo=utc)
            min_time = datetime.now(utc)

        for sid, last_visit in wl.get_watched_resources(
                'ticket', req.authname):
            ticketdict = {}
            try:
                ticket = Ticket(self.env, sid, db)
                exists = ticket.exists
            except:
                exists = False

            if not exists:
                ticketdict['deleted'] = True
                if 'id' in fields:
                    ticketdict['id'] = sid
                    ticketdict['ID'] = '#' + sid
                if 'author' in fields:
                    ticketdict['author'] = '?'
                if 'changetime' in fields:
                    ticketdict['changedsincelastvisit'] = 1
                    ticketdict['changetime'] = '?'
                    ticketdict['ichangetime'] = 0
                if 'time' in fields:
                    ticketdict['time'] = '?'
                    ticketdict['itime'] = 0
                if 'comment' in fields:
                    ticketdict['comment'] = tag.strong(t_("deleted"),
                                                       class_='deleted')
                if 'notify' in fields:
                    ticketdict['notify'] = wl.is_notify(req, 'ticket', sid)
                if 'description' in fields:
                    ticketdict['description'] = ''
                if 'owner' in fields:
                    ticketdict['owner'] = ''
                if 'reporter' in fields:
                    ticketdict['reporter'] = ''
                ticketlist.append(ticketdict)
                continue

            render_elt = lambda x: x
            if not (Chrome(self.env).show_email_addresses or \
                    'EMAIL_VIEW' in req.perm(ticket.resource)):
                render_elt = obfuscate_email_address

            # Copy all requested fields from ticket
            if fields:
                for f in fields:
                    ticketdict[f] = ticket.values.get(f, u'')
            else:
                ticketdict = ticket.values.copy()

            changetime = ticket.time_changed
            if wl.options['attachment_changes']:
                for attachment in Attachment.select(self.env, 'ticket', sid,
                                                    db):
                    if attachment.date > changetime:
                        changetime = attachment.date
            if 'attachment' in fields:
                attachments = []
                for attachment in Attachment.select(self.env, 'ticket', sid,
                                                    db):
                    wikitext = u'[attachment:"' + u':'.join([
                        attachment.filename, 'ticket', sid
                    ]) + u'" ' + attachment.filename + u']'
                    attachments.extend([
                        tag(', '),
                        format_to_oneliner(self.env,
                                           context,
                                           wikitext,
                                           shorten=False)
                    ])
                if attachments:
                    attachments.reverse()
                    attachments.pop()
                ticketdict['attachment'] = moreless(attachments, 5)

            # Changes are special. Comment, commentnum and last author are included in them.
            if 'changes' in fields or 'author' in fields or 'comment' in fields or 'commentnum' in fields:
                changes = []
                # If there are now changes the reporter is the last author
                author = ticket.values['reporter']
                commentnum = u"0"
                comment = u""
                want_changes = 'changes' in fields
                for date, cauthor, field, oldvalue, newvalue, permanent in ticket.get_changelog(
                        changetime, db):
                    author = cauthor
                    if field == 'comment':
                        if 'commentnum' in fields:
                            ticketdict['commentnum'] = to_unicode(oldvalue)
                        if 'comment' in fields:
                            comment = to_unicode(newvalue)
                            comment = moreless(comment, 200)
                            ticketdict['comment'] = comment
                        if not want_changes:
                            break
                    else:
                        if want_changes:
                            label = self.fields['ticket'].get(field, u'')
                            if label:
                                changes.extend([
                                    tag(
                                        tag.strong(label), ' ',
                                        render_property_diff(
                                            self.env, req, ticket, field,
                                            oldvalue, newvalue)),
                                    tag('; ')
                                ])
                if want_changes:
                    # Remove the last tag('; '):
                    if changes:
                        changes.pop()
                    changes = moreless(changes, 5)
                    ticketdict['changes'] = tag(changes)

            if 'id' in fields:
                ticketdict['id'] = sid
                ticketdict['ID'] = format_to_oneliner(self.env,
                                                      context,
                                                      '#' + sid,
                                                      shorten=True)
            if 'cc' in fields:
                if render_elt == obfuscate_email_address:
                    ticketdict['cc'] = ', '.join(
                        [render_elt(c) for c in ticketdict['cc'].split(', ')])
            if 'author' in fields:
                ticketdict['author'] = render_elt(author)
            if 'changetime' in fields:
                ichangetime = to_timestamp(changetime)
                ticketdict.update(
                    changetime=format_datetime(changetime,
                                               locale=locale,
                                               tzinfo=req.tz),
                    ichangetime=ichangetime,
                    changedsincelastvisit=(last_visit < ichangetime and 1
                                           or 0),
                    changetime_delta=pretty_timedelta(changetime),
                    changetime_link=req.href.timeline(
                        precision='seconds',
                        from_=trac_format_datetime(changetime,
                                                   'iso8601',
                                                   tzinfo=req.tz)))
                if changetime > max_changetime:
                    max_changetime = changetime
                if changetime < min_changetime:
                    min_changetime = changetime
            if 'time' in fields:
                time = ticket.time_created
                ticketdict.update(time=format_datetime(time,
                                                       locale=locale,
                                                       tzinfo=req.tz),
                                  itime=to_timestamp(time),
                                  time_delta=pretty_timedelta(time),
                                  time_link=req.href.timeline(
                                      precision='seconds',
                                      from_=trac_format_datetime(
                                          time, 'iso8601', tzinfo=req.tz)))
                if time > max_time:
                    max_time = time
                if time < min_time:
                    min_time = time
            if 'description' in fields:
                description = ticket.values['description']
                description = moreless(description, 200)
                ticketdict['description'] = description
            if 'notify' in fields:
                ticketdict['notify'] = wl.is_notify(req, 'ticket', sid)
            if 'owner' in fields:
                ticketdict['owner'] = render_elt(ticket.values['owner'])
            if 'reporter' in fields:
                ticketdict['reporter'] = render_elt(ticket.values['reporter'])
            if 'tags' in fields and self.tagsystem:
                tags = []
                for t in self.tagsystem.get_tags(req, Resource('ticket', sid)):
                    tags.extend(
                        [tag.a(t, href=req.href('tags', q=t)),
                         tag(', ')])
                if tags:
                    tags.pop()
                ticketdict['tags'] = moreless(tags, 10)

            ticketlist.append(ticketdict)

        if 'changetime' in fields:
            extradict['max_changetime'] = format_datetime(max_changetime,
                                                          locale=locale,
                                                          tzinfo=req.tz)
            extradict['min_changetime'] = format_datetime(min_changetime,
                                                          locale=locale,
                                                          tzinfo=req.tz)
        if 'time' in fields:
            extradict['max_time'] = format_datetime(max_time,
                                                    locale=locale,
                                                    tzinfo=req.tz)
            extradict['min_time'] = format_datetime(min_time,
                                                    locale=locale,
                                                    tzinfo=req.tz)

        return ticketlist, extradict
Beispiel #50
0
    def render_admin_panel(self, req, cat, page, path_info):
        """
        Returns the admin view and handles the form actions
        """
        req.perm.require('TRAC_ADMIN')

        project = Project.get(self.env)

        if req.method == 'POST':
            myprojects_url = conf.url_home_path + "/myprojects"
            conf.log.exception("Redirect URL: %s" % myprojects_url)
            thisurl = Href(req.base_path)(req.path_info)
            context = Context.from_request(req)

            # Handle project remove
            if 'remove' in req.args:
                # Don't allow removing home
                if project.env_name == conf.sys_home_project_name:
                    add_warning(req, 'Cannot remove home project')
                    return req.redirect(thisurl)

                # Archive the project before removal
                archive = ProjectArchive()
                archived = archive.archive(project)

                if not archived:
                    add_warning(
                        req,
                        'Could not archive project "%s". Will not remove the project'
                        % project.project_name)
                    return req.redirect(thisurl)

                # Notify listeners. The project object still exists, but database does not
                for listener in self.project_change_listeners:
                    listener.project_archived(project)

                # Do the actual project removal
                projects = Projects()
                if projects.remove_project(project):
                    # Notify listeners. The project object still exists, but database does not
                    for listener in self.project_change_listeners:
                        listener.project_deleted(project)

                    # NOTE: We no longer have project tables/session etc available
                    req.redirect(myprojects_url)

                else:
                    add_warning(
                        req, 'Could not remove project "%s". Try again later' %
                        project.project_name)
                    return req.redirect(thisurl)

        add_script(req, 'multiproject/js/jquery-ui.js')
        add_script(req, 'multiproject/js/multiproject.js')
        add_script(req, 'multiproject/js/admin_system.js')
        add_stylesheet(req, 'multiproject/css/jquery-ui.css')

        # NOTE: Trac automatically puts 'project' dict in chrome thus it cannot be used
        data = {
            'multiproject': {
                'project': project,
                'home_url': conf.url_home_path
            }
        }
        return 'admin_system.html', data
Beispiel #51
0
 def web_context(*args, **kwargs):
     return Context.from_request(*args, **kwargs)
Beispiel #52
0
    def render_macro(self, req, name, content):
        args = [x.strip() for x in content.split(',')]
        #        return args
        if len(args) == 1:
            args.append(None)
        elif len(args) != 2:
            return system_message('Invalid arguments "%s"' % content)

        # Pull out the arguments
        source, theader = args
        try:
            source_format, source_obj = source.split(':', 1)
        except ValueError:  # If no : is present, assume its a wiki page
            source_format, source_obj = 'source', source

        # Apply a default format if needed
        try:
            if theader is not None:
                isTheader, theader_content = theader.split("=", 1)
        except AttributeError:
            pass

        try:
            dest_format = self.default_formats[source_format]
        except KeyError:
            pass

        if source_format == 'source':
            if not req.perm.has_permission('FILE_VIEW'):
                return ''
            repo = self.env.get_repository(req.authname)
            node = repo.get_node(source_obj)
            out = node.get_content().read()
            if dest_format is None:
                dest_format = node.content_type or get_mimetype(
                    source_obj, out)
            ctxt = Context.from_request(req, 'source', source_obj)
        # RFE: Add ticket: and comment: sources. <NPK>
        # RFE: Add attachment: source. <NPK>
        else:
            return system_message('Unsupported include source %s' % source)

        # If we have a preview format, use it

        # Escape if needed
#        if not self.config.getbool('wiki', 'render_unsafe_content', False):
#            try:
#                out = HTMLParser(StringIO(out)).parse() | HTMLSanitizer()
#            except ParseError:
#                out = escape(out)
#        reader = str(out).split("||")
        need_header = 1
        foo = ''
        foo += '<table class="sortable"  style="border:1px solid #000;">'
        try:
            if theader is not None:
                if isTheader == "header":
                    custom_theader = theader_content.split(";")
                    foo += '<tr>'
                    for theader_cell in custom_theader:
                        foo += '<th style="border:1px solid #000;">' + str(
                            theader_cell) + '</th>'
                    foo += "</tr>\n"
        except AttributeError:
            pass

        for row in str(out).splitlines():
            foo += "<tr>\n"
            for cell in row.split("||"):
                if cell.startswith("|"):
                    foo += '<td align="right" style="border:1px solid #000;">'
                    if dest_format:
                        foo += (str(
                            Mimeview(self.env).render(
                                None, "text/x-trac-wiki",
                                str(cell.lstrip("|"))))[16:])[:-19]

                    foo += "</td>"
                else:
                    foo += '<td align="right" style="border:1px solid #000;">'
                    if dest_format:
                        foo += (str(
                            Mimeview(self.env).render(
                                None, "text/x-trac-wiki",
                                str(cell))).lstrip("<p>")[16:])[:-19]
                    foo += "</td>"
#            foo +=str(row)
#            for cell in row:
#                foo += cell
#                foo += "-"
        foo += "</tr></table>"

        return foo
Beispiel #53
0
    def process_request(self, req):
        """ Processing the request. """

        req.perm('blog').assert_permission('BLOG_VIEW')

        blog_core = FullBlogCore(self.env)
        format = req.args.get('format', '').lower()

        command, pagename, path_items, listing_data = self._parse_path(req)
        action = req.args.get('action', 'view').lower()
        try:
            version = int(req.args.get('version', 0))
        except:
            version = 0

        data = {}
        template = 'fullblog_view.html'
        data['blog_about'] = BlogPost(self.env, 'about')
        data['blog_infotext'] = blog_core.get_bloginfotext()
        blog_month_names = map_month_names(
            self.env.config.getlist('fullblog', 'month_names'))
        data['blog_month_names'] = blog_month_names
        self.env.log.debug(
            "Blog debug: command=%r, pagename=%r, path_items=%r" %
            (command, pagename, path_items))

        if not command:
            # Request for just root (display latest)
            data['blog_post_list'] = []
            count = 0
            maxcount = self.num_items
            blog_posts = get_blog_posts(self.env)
            for post in blog_posts:
                bp = BlogPost(self.env, post[0], post[1])
                if 'BLOG_VIEW' in req.perm(bp.resource):
                    data['blog_post_list'].append(bp)
                    count += 1
                if maxcount and count == maxcount:
                    # Only display a certain number on front page (from config)
                    break
            data['blog_list_title'] = "Recent posts" + \
                    (len(blog_posts) > maxcount and \
                        " (max %d) - Browse or Archive for more" % (maxcount,) \
                    or '')
            add_link(req, 'alternate', req.href.blog(format='rss'), 'RSS Feed',
                     'application/rss+xml', 'rss')

        elif command == 'archive':
            # Requesting the archive page
            template = 'fullblog_archive.html'
            data['blog_archive'] = []
            for period, period_posts in group_posts_by_month(
                    get_blog_posts(self.env)):
                allowed_posts = []
                for post in period_posts:
                    bp = BlogPost(self.env, post[0], post[1])
                    if 'BLOG_VIEW' in req.perm(bp.resource):
                        allowed_posts.append(post)
                if allowed_posts:
                    data['blog_archive'].append((period, allowed_posts))
            add_link(req, 'alternate', req.href.blog(format='rss'), 'RSS Feed',
                     'application/rss+xml', 'rss')

        elif command == 'view' and pagename:
            # Requesting a specific blog post
            the_post = BlogPost(self.env, pagename, version)
            req.perm(the_post.resource).require('BLOG_VIEW')
            if not the_post.version:
                raise HTTPNotFound("No blog post named '%s'." % pagename)
            if req.method == 'POST':  # Adding/Previewing a comment
                # Permission?
                req.perm(the_post.resource).require('BLOG_COMMENT')
                comment = BlogComment(self.env, pagename)
                comment.comment = req.args.get('comment', '')
                comment.author = (req.authname != 'anonymous' and req.authname) \
                            or req.args.get('author')
                comment.time = datetime.datetime.now(utc)
                warnings = []
                if 'cancelcomment' in req.args:
                    req.redirect(req.href.blog(pagename))
                elif 'previewcomment' in req.args:
                    warnings.extend(
                        blog_core.create_comment(req,
                                                 comment,
                                                 verify_only=True))
                elif 'submitcomment' in req.args and not warnings:
                    warnings.extend(blog_core.create_comment(req, comment))
                    if not warnings:
                        req.redirect(
                            req.href.blog(pagename) + '#comment-' +
                            str(comment.number))
                data['blog_comment'] = comment
                # Push all warnings out to the user.
                for field, reason in warnings:
                    if field:
                        add_warning(req, "Field '%s': %s" % (field, reason))
                    else:
                        add_warning(req, reason)
            data['blog_post'] = the_post
            context = Context.from_request(req,
                                           the_post.resource,
                                           absurls=format == 'rss' and True
                                           or False)
            data['context'] = context
            if format == 'rss':
                return 'fullblog_post.rss', data, 'application/rss+xml'
            # Regular web response
            context = Context.from_request(req, the_post.resource)

            data['blog_attachments'] = AttachmentModule(
                self.env).attachment_data(context)
            # Previous and Next ctxtnav
            prev, next = blog_core.get_prev_next_posts(req.perm, the_post.name)
            if prev:
                add_link(req, 'prev', req.href.blog(prev), prev)
            if next:
                add_link(req, 'next', req.href.blog(next), next)
            if arity(prevnext_nav) == 4:
                # 0.12 compat following trac:changeset:8597
                prevnext_nav(req, 'Previous Post', 'Next Post')
            else:
                prevnext_nav(req, 'Post')
            # RSS feed for post and comments
            add_link(req, 'alternate', req.href.blog(pagename, format='rss'),
                     'RSS Feed', 'application/rss+xml', 'rss')

        elif command in ['create', 'edit']:
            template = 'fullblog_edit.html'
            default_pagename = blog_core._get_default_postname(req.authname)
            the_post = BlogPost(self.env, pagename or default_pagename)
            warnings = []

            if command == 'create' and req.method == 'GET' and not the_post.version:
                # Support appending query arguments for populating intial fields
                the_post.update_fields(req.args)
            if command == 'create' and the_post.version:
                # Post with name or suggested name already exists
                if 'BLOG_CREATE' in req.perm and the_post.name == default_pagename \
                                    and not req.method == 'POST':
                    if default_pagename:
                        add_notice(
                            req, "Suggestion for new name already exists "
                            "('%s'). Please make a new name." % the_post.name)
                elif pagename:
                    warnings.append(
                        ('',
                         "A post named '%s' already exists. Enter new name." %
                         the_post.name))
                the_post = BlogPost(self.env, '')
            if command == 'edit':
                req.perm(the_post.resource).require(
                    'BLOG_VIEW')  # Starting point
            if req.method == 'POST':
                # Create or edit a blog post
                if 'blog-cancel' in req.args:
                    if req.args.get('action', '') == 'edit':
                        req.redirect(req.href.blog(pagename))
                    else:
                        req.redirect(req.href.blog())
                # Assert permissions
                if command == 'create':
                    req.perm(Resource('blog', None)).require('BLOG_CREATE')
                elif command == 'edit':
                    if the_post.author == req.authname:
                        req.perm(the_post.resource).require('BLOG_MODIFY_OWN')
                    else:
                        req.perm(the_post.resource).require('BLOG_MODIFY_ALL')

                # Check input
                orig_author = the_post.author
                if not the_post.update_fields(req.args):
                    warnings.append(('', "None of the fields have changed."))
                version_comment = req.args.get('new_version_comment', '')
                if 'blog-preview' in req.args:
                    warnings.extend(
                        blog_core.create_post(req,
                                              the_post,
                                              req.authname,
                                              version_comment,
                                              verify_only=True))
                elif 'blog-save' in req.args and not warnings:
                    warnings.extend(
                        blog_core.create_post(req, the_post, req.authname,
                                              version_comment))
                    if not warnings:
                        req.redirect(req.href.blog(the_post.name))
                context = Context.from_request(req, the_post.resource)
                data['context'] = context
                data['blog_attachments'] = AttachmentModule(
                    self.env).attachment_data(context)
                data['blog_action'] = 'preview'
                data['blog_version_comment'] = version_comment
                if (orig_author and orig_author != the_post.author) and (
                        not 'BLOG_MODIFY_ALL' in req.perm(the_post.resource)):
                    add_notice(req, "If you change the author you cannot " \
                        "edit the post again due to restricted permissions.")
                    data['blog_orig_author'] = orig_author
            for field, reason in warnings:
                if field:
                    add_warning(req, "Field '%s': %s" % (field, reason))
                else:
                    add_warning(req, reason)
            data['blog_edit'] = the_post

        elif command == 'delete':
            bp = BlogPost(self.env, pagename)
            req.perm(bp.resource).require('BLOG_DELETE')
            if 'blog-cancel' in req.args:
                req.redirect(req.href.blog(pagename))
            comment = int(req.args.get('comment', '0'))
            warnings = []
            if comment:
                # Deleting a specific comment
                bc = BlogComment(self.env, pagename, comment)
                if not bc.number:
                    raise TracError(
                        "Cannot delete. Blog post name and/or comment number missing."
                    )
                if req.method == 'POST' and comment and pagename:
                    warnings.extend(blog_core.delete_comment(bc))
                    if not warnings:
                        add_notice(req, "Blog comment %d deleted." % comment)
                        req.redirect(req.href.blog(pagename))
                template = 'fullblog_delete.html'
                data['blog_comment'] = bc
            else:
                # Delete a version of a blog post or all versions
                # with comments and attachments if only version.
                if not bp.version:
                    raise TracError(
                        "Cannot delete. Blog post '%s' does not exist." %
                        (bp.name))
                version = int(req.args.get('version', '0'))
                if req.method == 'POST':
                    if 'blog-version-delete' in req.args:
                        if bp.version != version:
                            raise TracError(
                                "Cannot delete. Can only delete most recent version."
                            )
                        warnings.extend(
                            blog_core.delete_post(bp, version=bp.versions[-1]))
                    elif 'blog-delete' in req.args:
                        version = 0
                        warnings.extend(
                            blog_core.delete_post(bp, version=version))
                    if not warnings:
                        if version > 1:
                            add_notice(
                                req, "Blog post '%s' version %d deleted." %
                                (pagename, version))
                            req.redirect(req.href.blog(pagename))
                        else:
                            add_notice(req,
                                       "Blog post '%s' deleted." % pagename)
                            req.redirect(req.href.blog())
                template = 'fullblog_delete.html'
                data['blog_post'] = bp
            for field, reason in warnings:
                if field:
                    add_warning(req, "Field '%s': %s" % (field, reason))
                else:
                    add_warning(req, reason)

        elif command.startswith('listing-'):
            # 2007/10 or category/something or author/theuser
            title = category = author = ''
            from_dt = to_dt = None
            if command == 'listing-month':
                from_dt = listing_data['from_dt']
                to_dt = listing_data['to_dt']
                title = "Posts for the month of %s %d" % (
                    blog_month_names[from_dt.month - 1], from_dt.year)
                add_link(req, 'alternate', req.href.blog(format='rss'),
                         'RSS Feed', 'application/rss+xml', 'rss')

            elif command == 'listing-category':
                category = listing_data['category']
                if category:
                    title = "Posts in category %s" % category
                    add_link(req, 'alternate',
                             req.href.blog('category', category, format='rss'),
                             'RSS Feed', 'application/rss+xml', 'rss')
            elif command == 'listing-author':
                author = listing_data['author']
                if author:
                    title = "Posts by author %s" % author
                    add_link(req, 'alternate',
                             req.href.blog('author', author, format='rss'),
                             'RSS Feed', 'application/rss+xml', 'rss')
            if not (author or category or (from_dt and to_dt)):
                raise HTTPNotFound("Not a valid path for viewing blog posts.")
            blog_posts = []
            for post in get_blog_posts(self.env,
                                       category=category,
                                       author=author,
                                       from_dt=from_dt,
                                       to_dt=to_dt):
                bp = BlogPost(self.env, post[0], post[1])
                if 'BLOG_VIEW' in req.perm(bp.resource):
                    blog_posts.append(bp)
            data['blog_post_list'] = blog_posts
            data['blog_list_title'] = title
        else:
            raise HTTPNotFound("Not a valid blog path.")

        if (not command or command.startswith('listing-')) and format == 'rss':
            data['context'] = Context.from_request(req, absurls=True)
            data['blog_num_items'] = self.num_items
            return 'fullblog.rss', data, 'application/rss+xml'

        data['blog_months'], data['blog_authors'], data['blog_categories'], \
                data['blog_total'] = \
                    blog_core.get_months_authors_categories(
                        user=req.authname, perm=req.perm)
        if 'BLOG_CREATE' in req.perm('blog'):
            add_ctxtnav(req,
                        'New Post',
                        href=req.href.blog('create'),
                        title="Create new Blog Post")
        add_stylesheet(req, 'tracfullblog/css/fullblog.css')
        add_stylesheet(req, 'common/css/code.css')
        data['blog_personal_blog'] = self.env.config.getbool(
            'fullblog', 'personal_blog')
        data['blog_archive_rss_icon'] = self.all_rss_icons \
                                        or self.archive_rss_icon
        data['blog_all_rss_icons'] = self.all_rss_icons
        return (template, data, None)
Beispiel #54
0
        master = BuildBotSystem(self.buildbot_url)
        if builder is None:
            data = {'names': master.getAllBuilders()}
            return 'bbw_allbuilders.html', data, 'text/html'
        else:

            class Foo:
                pass

            b = Foo()
            b.name = str(builder)
            b.current = 'CURRENT-TEXT'
            b.recent = []
            b.slaves = []
            data = {'builder': b}
            try:
                master = BuildBotSystem(self.buildbot_url)
                data = {'builder': master.getBuilder(builder)}
            except Exception, e:
                print 'Error fetching builder stats', e
            data['context'] = Context.from_request(req, ('buildbot', builder))
            return 'bbw_builder.html', data, 'text/html'

    def match_request(self, req):
        return req.path_info.startswith('/buildbot') and 1 or 0

    def process_request(self, req):
        if req.path_info.startswith('/buildbot/builder'):
            return self._handle_builder(req)
        return 'bbw_welcome.html', {'url': self.buildbot_url}, 'text/html'
Beispiel #55
0
    def _render_config(self, req, config_name):
        db = self.env.get_db_cnx()

        config = BuildConfig.fetch(self.env, config_name, db=db)
        if not config:
            raise HTTPNotFound("Build configuration '%s' does not exist." \
                                % config_name)

        repos = self.env.get_repository(req.authname)
        repos.authz.assert_permission(config.branch)

        data = {'title': 'Build Configuration "%s"' \
                          % config.label or config.name,
                'page_mode': 'view_config'}
        add_link(req, 'up', req.href.build(), 'Build Status')
        description = config.description
        if description:
            description = wiki_to_html(description, self.env, req)

        pending_builds = list(
            Build.select(self.env, config=config.name, status=Build.PENDING))
        inprogress_builds = list(
            Build.select(self.env,
                         config=config.name,
                         status=Build.IN_PROGRESS))

        rev = ''

        for b in repos.git.get_branches():
            if b[0] == config.branch:
                rev = b[1]
                break

        data['config'] = {
            'name': config.name,
            'label': config.label,
            'branch': config.branch,
            'active': config.active,
            'description': description,
            'browser_href': req.href.browser(rev=rev),
            'builds_pending': len(pending_builds),
            'builds_inprogress': len(inprogress_builds)
        }

        context = Context.from_request(req, config.resource)
        data['context'] = context
        data['config']['attachments'] = AttachmentModule(
            self.env).attachment_data(context)

        platforms = list(
            TargetPlatform.select(self.env, config=config_name, db=db))
        data['config']['platforms'] = [{
            'name':
            platform.name,
            'id':
            platform.id,
            'builds_pending':
            len(
                list(
                    Build.select(self.env,
                                 config=config.name,
                                 status=Build.PENDING,
                                 platform=platform.id))),
            'builds_inprogress':
            len(
                list(
                    Build.select(self.env,
                                 config=config.name,
                                 status=Build.IN_PROGRESS,
                                 platform=platform.id)))
        } for platform in platforms]

        has_reports = False
        for report in Report.select(self.env, config=config.name, db=db):
            has_reports = True
            break

        if has_reports:
            chart_generators = []
            for generator in ReportChartController(self.env).generators:
                for category in generator.get_supported_categories():
                    chart_generators.append({
                        'href':
                        req.href.build(config.name, 'chart/' + category)
                    })
            data['config']['charts'] = chart_generators
            charts_license = self.config.get('bitten', 'charts_license')
            if charts_license:
                data['config']['charts_license'] = charts_license

        page = max(1, int(req.args.get('page', 1)))
        more = False
        data['page_number'] = page

        repos = self.env.get_repository(req.authname)

        builds_per_page = 12 * len(platforms)
        idx = 0
        builds = {}
        for platform, rev, build in collect_changes(repos, config):
            if idx >= page * builds_per_page:
                more = True
                break
            elif idx >= (page - 1) * builds_per_page:
                builds.setdefault(rev, {})
                builds[rev].setdefault('href', req.href.changeset(rev))
                if build and build.status != Build.PENDING:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['steps'] = []
                    for step in BuildStep.select(self.env,
                                                 build=build.id,
                                                 db=db):
                        build_data['steps'].append({
                            'name': step.name,
                            'description': step.description,
                            'duration': to_datetime(step.stopped, utc) - \
                                        to_datetime(step.started, utc),
                            'failed': not step.successful,
                            'errors': step.errors,
                            'href': build_data['href'] + '#step_' + step.name
                        })
                    builds[rev][platform.id] = build_data
            idx += 1
        data['config']['builds'] = builds

        if page > 1:
            if page == 2:
                prev_href = req.href.build(config.name)
            else:
                prev_href = req.href.build(config.name, page=page - 1)
            add_link(req, 'prev', prev_href, 'Previous Page')
        if more:
            next_href = req.href.build(config.name, page=page + 1)
            add_link(req, 'next', next_href, 'Next Page')
        prevnext_nav(req, 'Page')
        return data
Beispiel #56
0
    def process_request(self, req):
        req.perm.require('BUILD_VIEW')

        db = self.env.get_db_cnx()
        build_id = int(req.args.get('id'))
        build = Build.fetch(self.env, build_id, db=db)
        if not build:
            raise HTTPNotFound("Build '%s' does not exist." \
                                % build_id)

        if req.method == 'POST':
            if req.args.get('action') == 'invalidate':
                self._do_invalidate(req, build, db)
            req.redirect(req.href.build(build.config, build.id))

        add_link(req, 'up', req.href.build(build.config),
                 'Build Configuration')
        data = {
            'title': 'Build %s - %s' % (build_id, _status_title[build.status]),
            'page_mode': 'view_build',
            'build': {}
        }
        config = BuildConfig.fetch(self.env, build.config, db=db)
        data['build']['config'] = {
            'name': config.label or config.name,
            'href': req.href.build(config.name)
        }

        context = Context.from_request(req, build.resource)
        data['context'] = context
        data['build']['attachments'] = AttachmentModule(
            self.env).attachment_data(context)

        formatters = []
        for formatter in self.log_formatters:
            formatters.append(formatter.get_formatter(req, build))

        summarizers = {}  # keyed by report type
        for summarizer in self.report_summarizers:
            categories = summarizer.get_supported_categories()
            summarizers.update(dict([(cat, summarizer) for cat in categories]))

        data['build'].update(_get_build_data(self.env, req, build))
        steps = []
        for step in BuildStep.select(self.env, build=build.id, db=db):
            steps.append({
                'name':
                step.name,
                'description':
                step.description,
                'duration':
                pretty_timedelta(step.started, step.stopped),
                'failed':
                step.status == BuildStep.FAILURE,
                'errors':
                step.errors,
                'log':
                self._render_log(req, build, formatters, step),
                'reports':
                self._render_reports(req, config, build, summarizers, step)
            })
        data['build']['steps'] = steps
        data['build']['can_delete'] = ('BUILD_DELETE' in req.perm \
                                   and build.status != build.PENDING)

        repos = self.env.get_repository(req.authname)
        repos.authz.assert_permission(config.branch)
        chgset = repos.get_changeset(build.rev)
        data['build']['chgset_author'] = chgset.author

        add_script(req, 'common/js/folding.js')
        add_script(req, 'bitten/tabset.js')
        add_stylesheet(req, 'bitten/bitten.css')
        return 'bitten_build.html', data, None
Beispiel #57
0
                urlf = urllib2.urlopen(source)
                out = urlf.read()  
            except urllib2.URLError, e:
                return system_message('Error while retrieving file', str(e))
            except TracError, e:
                return system_message('Error while previewing', str(e))
            ctxt = Context.from_request(req)
        elif source_format == 'wiki':
            # XXX: Check for recursion in page includes. <NPK>
            if not req.perm.has_permission('WIKI_VIEW'):
                return ''
            page = WikiPage(self.env, source_obj)
            if not page.exists:
                return system_message('Wiki page %s does not exist'%source_obj)
            out = page.text
            ctxt = Context.from_request(req, 'wiki', source_obj)
        elif source_format == 'source':
            if not req.perm.has_permission('FILE_VIEW'):
                return ''
            repo = self.env.get_repository(authname=req.authname)
            node = repo.get_node(source_obj)
            out = node.get_content().read()
            if dest_format is None:
                dest_format = node.content_type or get_mimetype(source_obj, out)
            ctxt = Context.from_request(req, 'source', source_obj)
        # RFE: Add ticket: and comment: sources. <NPK>
        # RFE: Add attachment: source. <NPK>
        else:
            return system_message('Unsupported include source %s'%source)

        # If there was a fragment name given then find the fragment.
def format_to_html(req, env, text):
    req = Mock(href=Href('/'), abs_href=Href('http://www.example.com/'),
               authname='anonymous', perm=MockPerm(), args={})
    context = Context.from_request(req)
    return trac.wiki.formatter.format_to_html(env, context, text)
Beispiel #59
0
    def convert_content(self, req, input_type, source, output_type):

        # get parameters from trac ini file
        self.img_max_x = self.env.config.get('pagetodoc', 'img_max_x', self.img_max_x)
        self.img_max_y = self.env.config.get('pagetodoc', 'img_max_y', self.img_max_y)
        self.img_max_y = self.env.config.get('pagetodoc', 'dpi', self.dpi)

        # XSL-Transformation        
        xsltfilepath = self.env.config.get('pagetodoc', 'xsltfile', '')
        # TBD: Fehler ausgeben, wenn xsltfile nicht gelesen werden kann
        # TBD: Parameter aus der trac.ini an zentraler Stelle auslesen
        if xsltfilepath == '':
            message = "You have to set the 'xsltfile' option in the " \
                "[pagetodoc] section in trac.ini"
            raise_dependency_issue(message, req, self.env)
        if not os.path.exists(xsltfilepath):
            message = ("Value for 'xsltfile' in the [pagetodoc] section in " \
                "trac.ini does not exist: '%s'.")% xsltfilepath
            raise_dependency_issue(message, req, self.env)

        # maybe for later use
        #codepage = self.env.config.get('trac', 'charset', 'iso-8859-1')
        codepage = 'iso-8859-1'

        # Convert Wiki markup to HTML, new style
        out = StringIO()
        context = Context.from_request(req, 'wiki', req.path_info[6:])
        Formatter(self.env, context).format(source, out)
        html = Markup(out.getvalue()).encode(codepage, 'replace')

        # remove the bad HTML produced by the breadcrumbs plugin
        # RFE: find a universal way to do this
        html = re.compile('(<lh[^>]*>)').sub('', html)

        # temporary files and folders
        self.tempdir = mkdtemp(prefix="page2doc")
        htmlfilehandle, htmlfilepath = mkstemp(prefix='trac_', dir=self.tempdir, suffix = ".html")
        wordfilehandle, wordfilepath = mkstemp(prefix='word_', dir=self.tempdir, suffix = ".doc")
        os.close(wordfilehandle)

        # for debug: set all rights
        #self.chmod_tmp_dir(self.tempdir)

        # images
        # replace href with absolute path and if existing, base auth login
        try:
            # this will work if the authentication type is basic (and not over SSL?)
            login = base64.b64decode(req.environ['HTTP_AUTHORIZATION'][6:]) + '@'                  
        except (KeyError, TypeError):
            login = ''
                   
        html = re.sub('<img src="(?!\w+://)', '<img src="%s://%s%s:%d' % (req.scheme, login, req.server_name, req.server_port), html)

        # save images to disk
        html = re.sub('<img src="([^"]*)"', self.download_image, html)

        # write HTML page to disk
        os.write(htmlfilehandle, '<html><body>' + html + '</body></html>')
        os.close(htmlfilehandle)

        # clean up the HTML page using HTML Tidy
        args = '-m -asxhtml -latin1 --doctype omit'
        tidypath = self.env.config.get('pagetodoc', 'tidypath', 'tidy')

        # verify that Tidy exists and is setup correctly
        tidy_error = dependency_failure("tidy", tidypath, "-v")

        if tidy_error:
            raise_dependency_issue(tidy_error, req, self.env)

        cmd = '"%s" %s %s' % (tidypath, args, htmlfilepath)
        self.execute_external_program(cmd)

        # workaround namespace
        self.perform_workarounds(htmlfilepath, 'html')

        if self.verbose:
            verb = '-v'
        else:
            verb = ''
        xsltprocpath = self.env.config.get('pagetodoc', 'xsltprocpath', 'xsltproc')

        # verify that Tidy exists and is setup correctly
        xsltproc_error = dependency_failure("xsltproc", xsltprocpath, "-V")

        if xsltproc_error:
            raise_dependency_issue(xsltproc_error, req, self.env)

        cmd = '%s %s --html -o %s %s %s' % (
            xsltprocpath, verb, wordfilepath, xsltfilepath, htmlfilepath)
        self.execute_external_program(cmd)

        # workaround pre-tags
        self.perform_workarounds(wordfilepath, 'pre')

        zipfilepath = os.path.join(
            self.tempdir, os.path.basename(str(req.path_info) + '.zip'))
            
        # create a zip file and store all files into it      
        zipfilehandle = zipfile.ZipFile(zipfilepath, "w")
        zipfilehandle.write(wordfilepath, os.path.basename(str(req.path_info) + '.htm'))       
        for image in self.images:
            zipfilehandle.write(image, self.imagesubdir + os.path.basename(image))     
        zipfilehandle.close()
        zip_file = open(zipfilepath, "rb")
        zip = zip_file.read()
        zip_file.close()

        # delete temporary folders and files
        self.remove_dir(os.path.join(self.tempdir, self.logsubdir))
        self.remove_dir(os.path.join(self.tempdir, self.imagesubdir))
        self.remove_dir(self.tempdir)

        # reset image list
        self.images = []

        return (zip, 'application/zip')
Beispiel #60
0
    def _render_templates(self, req, cat, page, component):
        req.perm.assert_permission('TRAC_ADMIN')

        for key, value in req.args.items():
            self.env.log.debug("Key: %s, Value: %s", key, value)

        testmanagersystem = TestManagerSystem(self.env)

        context = Context.from_request(req)

        data = {}

        data['template_overview'] = True
        data['edit_template'] = False

        data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
        data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)
        data['tcat_list'] = testmanagersystem.get_testcatalogs()
        data['tcat_selected'] = testmanagersystem.get_default_tcat_template_id()

        if req.method == 'POST':
            
            # add a Test Case template?
            if req.args.get('tc_add'):
                tc_name = req.args.get('tc_add_name')
                self.env.log.debug("Add new TC-template: %s" % tc_name)

                if len(tc_name) > 0:
                    if testmanagersystem.template_exists(tc_name, testmanagersystem.TEMPLATE_TYPE_TESTCASE):
                        data['tc_add_name'] = tc_name
                        add_warning(req, _("A Test Case template with that name already exists"))
                    else:
                        data['template_overview'] = False
                        data['edit_template'] = True
                        data['t_edit_type'] = testmanagersystem.TEMPLATE_TYPE_TESTCASE
                        data['t_edit_name'] = tc_name
                        data['t_edit_action'] = 'ADD'
                else:
                    add_warning(req, _("Please enter a Template name first"))

            # add a Test Catalog template?
            if req.args.get('tcat_add'):
                tcat_name = req.args.get('tcat_add_name')
                self.env.log.debug("Add new TCat-template: %s" % tcat_name)

                if len(tcat_name) > 0:
                    if testmanagersystem.template_exists(tcat_name, testmanagersystem.TEMPLATE_TYPE_TESTCATALOG):
                        data['tcat_add_name'] = tcat_name
                        add_warning(req, _("A Test Catalog template with that name already exists"))
                    else:
                        data['template_overview'] = False
                        data['edit_template'] = True
                        data['t_edit_type'] = testmanagersystem.TEMPLATE_TYPE_TESTCATALOG
                        data['t_edit_name'] = tcat_name
                        data['t_edit_action'] = 'ADD'
                else:
                    add_warning(req, _("Please enter a Template name first"))

            # delete a Test Case template?
            if req.args.get('tc_del'):
                tc_sel = req.args.get('tc_sel')
                for t_id in tc_sel:
                    t = testmanagersystem.get_template_by_id(t_id)
                    if testmanagersystem.template_in_use(t_id):
                        add_warning(req, _("Template '%s' not removed as it is in use for a Test Catalog") % t['name'])
                        continue
                    
                    self.env.log.debug("remove test case template with id: " + t_id)
                    if not testmanagersystem.remove_template(t_id):
                        add_warning(req, _("Error deleting Test Case template '%s'") % t['name'])
                    else:
                        add_notice(req, _("Test Case template '%s' deleted") % t['name'])
                    
                data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
                data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)

            # delete a Test Catalog template?
            if req.args.get('tcat_del'):
                tcat_sel = req.args.get('tcat_sel')
                tcat_default = testmanagersystem.get_default_tcat_template_id()
                for t_id in tcat_sel:
                    t = testmanagersystem.get_template_by_id(t_id)
                    if t_id == tcat_default:
                        add_warning(req, _("Template '%s' not removed as it is currently the default template") % t['name'])
                        continue
                    
                    self.env.log.debug("remove test catalog template with id: " + t_id)
                    if not testmanagersystem.remove_template(t_id):
                        add_warning(req, _("Error deleting Test Catalog template '%s'") % t['name'])
                    else:
                        add_notice(req, _("Test Catalog template '%s' deleted") % t['name'])
                        
                data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
                data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)

            # save default Test Catalog template
            if req.args.get('tcat_default_save'):
                tcat_default = req.args.get('tcat_default')
                if testmanagersystem.set_config_property('TEST_CATALOG_DEFAULT_TEMPLATE', tcat_default):
                    add_notice(req, _("Default Test Catalog template updated"))
                    data['tcat_selected'] = tcat_default
                else:
                    add_warning(req, _("Failed to update default Test Catalog template"))

            # save templates for TestCatalogs
            if req.args.get('tc_templates_save'):
                warning = False
                for key, value in req.args.items():
                    self.env.log.debug("checking key: " + key)
                    if 'TC_TEMPLATE_FOR_TCAT_' in key:
                        self.env.log.debug("saving tc-template for: %s, value: %s" % (key, value))
                        if not testmanagersystem.set_config_property(key, value):
                            warning = True
                if warning:
                    add_warning(req, _("Failed to update Test Case templates"))
                else:
                    add_notice(req, _("Default Test Case templates updated"))
                    data['tcat_list'] = testmanagersystem.get_testcatalogs()

            # preview template
            if req.args.get('t_edit_preview'):
                data['template_overview'] = False
                data['edit_template'] = True
                data['t_edit_id'] = req.args.get('t_edit_id')
                data['t_edit_type'] = req.args.get('t_edit_type')
                data['t_edit_name'] = req.args.get('t_edit_name')
                data['t_edit_description'] = req.args.get('t_edit_description')
                data['t_edit_content'] = req.args.get('t_edit_content')
                data['t_edit_action'] = req.args.get('t_edit_action')
                data['t_show_preview'] = True
                data['t_preview_content'] = format_to_html(self.env, context, req.args.get('t_edit_content'))

            # save an edited template?
            if req.args.get('t_edit_save'):
                t_id = req.args.get('t_edit_id')
                t_type = req.args.get('t_edit_type')
                t_name = req.args.get('t_edit_name')
                t_desc = req.args.get('t_edit_description')
                t_cont = req.args.get('t_edit_content')
                t_action = req.args.get('t_edit_action')

                testmanagersystem.save_template(t_id, t_name, t_type, t_desc, t_cont, t_action)

                data['template_overview'] = True
                data['edit_template'] = False
                data['tc_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCASE)
                data['tcat_templates'] = testmanagersystem.get_templates(testmanagersystem.TEMPLATE_TYPE_TESTCATALOG)
                add_notice(req, _("Template saved"))

        else:
            # method 'GET' (template selected for 'edit')
            if component:
                t_type = req.args.get('t_type')
                t_id = component
                self.env.log.debug("component: " + component)
                template = testmanagersystem.get_template_by_id(t_id)

                data['t_edit_id'] = template['id']
                data['t_edit_type'] = template['type']
                data['t_edit_name'] = template['name']
                data['t_edit_description'] = template['description']
                data['t_edit_content'] = template['content']
                data['t_edit_action'] = 'EDIT'

                data['template_overview'] = False
                data['edit_template'] = True

        add_stylesheet(req, 'common/css/wiki.css')
        add_stylesheet(req, 'testmanager/css/admin.css')
        return 'admin_templates.html', data