Пример #1
0
    def commentonticket( self, projectname, ticket, comment ) :
        """
        === commentonticket( projectname, ticket, comment )
        
        :Description ::
            Comment on `ticket` under project `projectname`

        Positional arguments,
        |= projectname | a valid project-name
        |= ticket      | a valid ticket id
        |= comment     | comment as wiki text

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        commentor = c.authuser
        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'TICKET_COMMENT_CREATE' ))
              )
        if res :
            return res
        else :
            rc, tcmt, failmsg = xicomp.comment_ticket(  
                                    unicode(projectname), int(ticket),
                                    unicode(comment), commentor
                                )
            return _result( rc, failmsg=failmsg )
Пример #2
0
    def vcs_browse(self, environ, projectname, vcsid):
        """Browse repository
        URLS :
            /p/{projectname}/s/{vcsid}/browse
            /p/{projectname}/s/{vcsid}/browse?revno=<num>
            /p/{projectname}/s/{vcsid}/browse?repospath=<rooturl>&revno=<num>
                                             &jsonobj=dirlist&view=js
            /p/{projectname}/s/{vcsid}/browse?filepath=<path>&revno=<num>
        """
        from zeta.config.environment import projcomp, vcscomp

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.rootdir = basename(c.vcs.rooturl.rstrip('/'))
        c.vcseditable = h.authorized(h.HasPermname('VCS_CREATE'))
        c.contents = vcscomp.mountcontents
        c.title = '%s:browse' % c.vcs.name

        # HTML page generation
        if c.jsonobj and c.view == 'js':
            html = self.handlejson(environ)

        else:
            c.pmounts = vcscomp.projmounts(c.project)
            fn = lambda mnt: [
                mnt[0], h.fix2repospath(mnt[3], [mnt[7]]).lstrip('/')
            ]
            c.mountdirs = map(fn, c.pmounts)
            html = render('/derived/projects/vcsbrowse.html')

        c.rclose.append(html)
        return c.rclose
Пример #3
0
    def listtickets( self, projectname ) :
        """
        === listtickets( projectname )
        
        :Description ::
            List all tickets under project `projectname`,

        Positional arguments,
        |= projectname | a valid project-name

        :Return ::
            On success,
                [<PRE
                { 'rpcstatus' : 'ok',
                  'tickets' : { <ticket-id> : [ <summary> ], ... }
                } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'TICKET_VIEW' ))
              )
        if res :
            return res
        else :
            rc, d, failmsg = xicomp.list_ticket( unicode(projectname) )
            return _result( rc, d=d, failmsg=failmsg )
Пример #4
0
    def commentonwiki( self, projectname, pagename, comment ) :
        """
        === commentonwiki( projectname, pagename, comment )

        :Description ::
            Comment on wiki-page, `pagename under project, `projectname`,

        Positional arguments,
        |= projectname | a valid project-name
        |= pagename    | valid and existing wiki page-name
        |= comment     | comment as wiki text

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        wikiurl = unicode(self.url_wikiurl( projectname, self._stripurl( pagename) ))
        commentor = c.authuser
        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'WIKICOMMENT_CREATE' ))
              )
        if res :
            return res
        else :
            rc, wcmt, failmsg = xicomp.comment_wiki( unicode(projectname), wikiurl,
                                                     unicode(comment), commentor )
            return _result( rc, failmsg=failmsg )
Пример #5
0
    def publishwiki( self, projectname, pagename, content ) :
        """
        === publishwiki( projectname, pagename, content )
        
        :Description ::
            Publish new content, (or updated content) for wiki-page `pagename`,
            under project, `projectname`,

        Positional arguments,
        |= projectname | a valid project-name
        |= pagename    | valid and existing wiki page-name
        |= content     | content to be published (as the next version).

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        wikiurl = unicode(self.url_wikiurl( projectname, self._stripurl( pagename) ))
        author  = c.authuser
        res     = self._permissions(
                        c.authuser, h.authorized( h.HasPermname( 'WIKI_CREATE' ))
                  )
        if res :
            return res
        else :
            rc, wiki, failmsg = xicomp.update_wiki( unicode(projectname), wikiurl,
                                                    unicode(content), author )
            return _result( rc, failmsg=failmsg )
Пример #6
0
    def listwikipages( self, projectname ) :
        """
        === listwikipage( projectname )

        :Description ::
            List wiki pages under project, `projectname`,

        Positional arguments,
        |= projectname | a valid project-name

        :Return ::
            On success,
                [<PRE
                { 'rpcstatus' : 'ok',
                  'wikipages' : [ <page-name>, <page-name>, .... ]
                } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'WIKI_VIEW' ))
              )
        if res :
            return res
        else :
            rc, wikipages, failmsg = xicomp.list_wiki( unicode(projectname) )
            return _result( True, d={ 'wikipages' : sorted(wikipages) })
Пример #7
0
    def vcs_revlist(self, environ, projectname, vcsid):
        """Browse repository
        URLS :
            /p/{projectname}/s/{vcsid}/revlist?revno=<num>
        """
        from zeta.config.environment import projcomp

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.projsummary = c.project.summary
        c.replogs = c.vrep.logs(c.vcs.rooturl,
                                revstart=c.vrep.finfo['l_revision'],
                                revend=c.vrep.linfo['l_revision'])

        # Create revision url for each log.
        c.revpages = [[
            c.replogs[i][1],
            self.url_vcsrevlist(projectname, vcsid, revno=c.replogs[i][1])
        ] for i in range(0, len(c.replogs), 100)]
        c.revpages.reverse()

        adj = c.vrep.client.start_revno
        c.revlist = [
            log + [
                self.url_vcsrev(projectname, vcsid, revno=log[1]),
            ] for log in c.replogs[(c.revno - adj):c.revno + 100 - adj]
        ]
        c.revlist.reverse()
        c.vcseditable = h.authorized(h.HasPermname('VCS_CREATE'))
        c.title = '%s:revlist' % c.vcs.name

        # Html page generation
        c.rclose.append(render('/derived/projects/vcsrevlist.html'))
        return c.rclose
Пример #8
0
    def create( self, environ ) :
        """Create and host a new project
        URLS :
            /p/newproject?form=request&formname=createprj
            /p/newproject?form=submit&formname=createprj
        """
        from zeta.config.environment    import liccomp, projcomp, vfcomp

        c.rclose = h.ZResp()

        # Form handling
        def errhandler(errmsg) :
            c.errmsg = errmsg
        vfcomp.process(
            request, c, defer=True, errhandler=h.hitchfn(errhandler),
            formnames=['createprj'], user=c.authuser
        )

        # Setup context for page generation
        c.licensenames = sorted([ l[1] for l in liccomp.licensefields() ])
        c.projectnames = projcomp.projectnames
        c.liceditable  = h.authorized( h.HasPermname(['LICENSE_CREATE']) )
        c.title = 'CreateProject'

        # Html page generation
        if c.errmsg :
            html = self.returnerrmsg(environ)
        elif c.form == 'submit' :
            h.redirect_url( h.url_createprj )
        else :
            html = render( '/derived/projects/create.html' )
        c.rclose.append(html)
        return c.rclose
Пример #9
0
    def timeline(self, environ, projectname, revwid=''):
        """Aggregate activities under project review or individual review
        URLS :
            /p/{projectname}/r/timeline/{revwid}
        """
        from zeta.config.environment import projcomp, revcomp

        c.rclose = h.ZResp()

        logid = request.params.get('logid', None)
        dir = request.params.get('dir', None)
        fromoff = request.params.get('fromoff', 1)
        logid = logid and int(logid)
        fromoff = int(fromoff)

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.review = revwid and revcomp.get_review(int(revwid)) or None
        c.revweditable = h.authorized(h.HasPermname('REVIEW_CREATE'))
        routeargs = {'projectname': projectname, 'revwid': revwid}
        self.tline_controller(h.r_projrevwtline, routeargs, 'review', fromoff,
                              logid, dir, c.review)
        c.title = 'Review:%s:timeline' % c.review.id
        c.datatline, c.startdt = h.tlineplot(c.logs[:])
        c.rclose.append(render('/derived/projects/reviewtline.html'))
        return c.rclose
Пример #10
0
    def tos(self, environ):
        """Static Wiki - Terms of Service
        .... Deprecated ....
        """
        from zeta.config.environment import syscomp

        c.rclose = h.ZResp()
        c.sweditable = h.authorized(h.HasPermname('STATICWIKI_CREATE'))
        c.swiki = syscomp.get_staticwiki(u'tos')
        c.swhtml = c.swiki and c.swiki.texthtml or ''

        c.rclose.append(render('/derived/home/guestwiki.html'))
        return c.rclose
Пример #11
0
    def attachs(self, environ):
        """Action to present attachment page for all license
        URLS : 
            /license/attachs
        """
        from zeta.config.environment import liccomp, vfcomp

        c.rclose = h.ZResp()
        c.editable = h.authorized(h.HasPermname('LICENSE_CREATE'))
        c.attachments = self.attachments(liccomp.attachments())
        c.title = 'LicenseAttachs'

        # Html page generation
        c.rclose.append(render('/derived/license/licattachs.html'))
        return c.rclose
Пример #12
0
    def index(self, environ):
        """Static Wiki - Home page.
        URLS :
            /
        """
        from zeta.config.environment import syscomp

        c.rclose = h.ZResp()
        # Setup context for page generation
        c.sweditable = h.authorized(h.HasPermname('STATICWIKI_CREATE'))
        c.swiki = syscomp.get_staticwiki(u'frontpage')
        c.title = config['zeta.sitename']
        c.swhtml = c.swiki and c.swiki.texthtml or ''

        c.rclose.append(render('/derived/home/guestwiki.html'))
        return c.rclose
Пример #13
0
    def wikiindex(self, environ, projectname):
        """Project wiki pages.
        URLS :
            /p/{projectname}/wiki
            /p/{projectname}/wiki?jsonobj=wikilist&view=js
            /p/{projectname}/wiki?form=submit&formname=vcsfile2wiki&view=js
            /p/{projectname}/wiki?form=submit&formname=configwiki&view=js
        """
        from zeta.config.environment import projcomp, wikicomp, vfcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        if self.formpermission():
            c.errmsg = 'Do not have %s permission !!' % tckperm[c.formname]
        else:
            vfcomp.process(
                request,
                c,
                defer=True,
                errhandler=h.hitchfn(errhandler),
                formnames=['vcsfile2wiki', 'configwiki'],
            )

        # Setup context for page generation
        c.projsummary = c.project.summary
        if not c.jsonobj and c.formname != 'vcsfile2wiki':
            c.wikitypenames = wikicomp.typenames
            c.wikipagenames = self.wikipagename(wikicomp.wikiurls(c.project))
            c.wikipagename = None
            c.wikieditable = h.authorized(h.HasPermname('WIKI_CREATE'))
            c.title = '%s:wiki' % projectname

        # HTML page generation
        html = ''
        if c.errmsg:
            html = self.returnerrmsg(environ)
        elif c.view == 'js' and c.jsonobj:
            html = self.handlejson(environ)
        elif c.view != 'js':
            html = render('/derived/projects/wikiindex.html')
        c.rclose.append(html)
        return c.rclose
Пример #14
0
    def attachs(self, environ, projectname):
        """Action to present attachment page for wiki pages under project 
        `projectname`
        URLS : 
            p/{projectname}/wiki/attachs
        """
        from zeta.config.environment import wikicomp, vfcomp

        c.rclose = h.ZResp()
        c.projsummary = c.project.summary
        c.wikipagenames = self.wikipagename(wikicomp.wikiurls(c.project))
        attachments = wikicomp.attachments(c.project)
        c.attachments = self.attachments(attachments)
        c.editable = h.authorized(h.HasPermname('WIKI_CREATE'))
        c.title = 'WikiAttachs'
        c.rclose.append(render('/derived/projects/wikiattachs.html'))
        return c.rclose
Пример #15
0
    def attachs(self, environ, projectname):
        """Action to present attachment page for tickets under project 
        `projectname`
        URLS :
            /p/{projectname}/t/attachs
        """
        from zeta.config.environment import vfcomp, tckcomp

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        attachments = tckcomp.attachments(c.project)
        c.attachments = self.attachments(attachments)
        c.editable = h.authorized(h.HasPermname('TICKET_CREATE'))
        c.title = 'TicketAttachs'
        c.rclose.append(render('/derived/projects/tckattachs.html'))
        return c.rclose
Пример #16
0
    def attachs(self, environ, projectname):
        """Action to present attachment page for reviews under project 
        `projectname`
        URLS :
            /p/{projectname}/r/attachs
        """
        from zeta.config.environment import revcomp, vfcomp

        c.rclose = h.ZResp()

        # Setup context for html page
        c.projsummary = c.project.summary
        attachments = revcomp.attachments(c.project)
        c.attachments = self.attachments(attachments)
        c.editable = h.authorized(h.HasPermname('REVIEW_CREATE'))
        c.title = 'ReviewAttachs'
        c.rclose.append(render('/derived/projects/revwattachs.html'))
        return c.rclose
Пример #17
0
    def vcsindex(self, environ, projectname):
        """Project source control
        URLS :
            /p/{projectname}/s
            /p/{projectname}/s?jsonobj=vcslist&view=js
            /p/{projectname}/s?form=submit&formname=configvcs&view=js
        """
        from zeta.config.environment import vfcomp, projcomp, vcscomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        if self.formpermission():
            c.errmsg = 'Do not have %s permission !!' % tckperm[c.formname]
        else:
            vfcomp.process(
                request,
                c,
                defer=True,
                errhandler=h.hitchfn(errhandler),
                formnames=['configvcs'],
            )

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.vcs_typenames = vcscomp.vcstypenames
        c.vcseditable = h.authorized(h.HasPermname('VCS_CREATE'))
        c.title = '%s:source' % projectname

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)
        elif c.view == 'js' and c.jsonobj:
            html = self.handlejson(environ)
        elif c.view != 'js':
            html = render('/derived/projects/vcsindex.html')
        else:
            html = ''

        c.rclose.append(html)
        return c.rclose
Пример #18
0
    def titleindex(self, environ):
        """Static Wiki - titleindex
        URLS :
            /titleindex
            /TitleIndex
        """
        from zeta.config.environment import syscomp

        c.rclose = h.ZResp()
        c.sweditable = h.authorized(h.HasPermname('STATICWIKI_CREATE'))
        c.swikis = [(sw.id, sw.path, self.url_editsw(sw.path),
                     self.suburl_delsw(sw.path))
                    for sw in syscomp.get_staticwiki()]
        c.swikis = sorted(c.swikis, key=lambda sw: sw[1])
        c.swa = ca.get_analyticobj('staticwiki')
        c.swsnippets = getattr(c.swa, 'pagesnippets', {})
        c.title = 'TitleIndex'
        c.rclose.append(render('/derived/home/titleindex.html'))
        return c.rclose
Пример #19
0
    def newwikipage( self, projectname, pagename, wtype, summary, sourceurl ) :
        """
        === newwikipage( projectname, wtype, summary, sourceurl )

        :Description ::
            Create a new wiki-page for project, `projectname`.

        Positional arguments,
        |= projectname | a valid project-name
        |= pagename    | new wiki page-name under project,
        |= wtype       | type of wiki page, if False, default type will be used
        |= summary     | summary string, if False, will assume empty string
        |= sourceurl   | source url, if False, will assume empty string

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        wikiurl = unicode(self.url_wikiurl( projectname, self._stripurl( pagename) ))
        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'WIKI_CREATE' ))
              )
        if res :
            return res
        else :
            wtype, summary, sourceurl = \
                    self._demarshalNone( wtype, summary, sourceurl )
            rc, wiki, failmsg = xicomp.create_wiki( unicode(projectname),
                                                    wikiurl,
                                                    wtype=unicode(wtype),
                                                    summary=unicode(summary),
                                                    sourceurl=unicode(sourceurl),
                                                    byuser=c.authuser
                                                  )
            return _result( rc, failmsg=failmsg )
Пример #20
0
    def newstaticwiki( self, path, content, swtype, sourceurl ) :
        """
        === newstaticwiki( path, content )

        :Description ::
            Create a new static wiki page, under path-url `path`, published
            with `content`
        
        Positional arguments,
        |= path      | url-path, for the new static wiki page
        |= content   | wiki text to publish.
        |= wtype     | type of wiki page, if False, will be skipped
        |= sourceurl | source url, if False, will be skipped

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        res = self._permissions(
                    c.authuser,
                    h.authorized( h.HasPermname( 'STATICWIKI_CREATE' ))
              )
        if res : 
            return res
        else :
            path = self._stripurl( path )
            swtype, sourceurl = self._demarshalNone( swtype, sourceurl )
            rc, sw, failmsg = xicomp.create_sw(
                                    path, unicode(content), swtype=swtype,
                                    sourceurl=sourceurl
                              )
            return _result( rc, failmsg=failmsg )
Пример #21
0
    def licenses(self, environ):
        """Action for all license pages.
        URLS :
            /license
            /license?form=submit&formname=rmlic&view=js
        """
        from zeta.config.environment import liccomp, vfcomp

        c.rclose = h.ZResp()

        # Form handling
        def errhandler(errmsg):
            c.errmsg = errmsg

        c.liceditable = h.authorized(h.HasPermname(['LICENSE_CREATE']))
        c.att_editable = c.liceditable
        c.tag_editable = c.liceditable
        if c.form == 'submit' and c.liceditable:
            vfcomp.process(request,
                           c,
                           defer=True,
                           errhandler=h.hitchfn(errhandler),
                           formnames=['rmlic'],
                           user=c.authuser)
        else:
            c.errmsg = 'Need `LICENSE_CREATE` to access the page'

        # Setup context for page generation
        c.licprojects = c.licensetable = []
        c.licensenames, c.licenselist, licfields = self._selectoptions()
        c.licensetable = self._lictable(licfields)
        c.attachs = {}
        c.tags = {}
        c.title = 'LicenseTable'

        # Html page generation
        c.rclose.append(render('/derived/license/license.html'))
        return c.rclose
Пример #22
0
    def wiki( self, projectname, pagename ) :
        """
        === wiki( projectname, pagename )

        :Description ::
            Read wiki-page `pagename`, for project, `projectname`,

        Positional arguments,
        |= projectname | a valid project-name
        |= pagename    | valid and existing wiki page-name

        :Return ::
            On success,
                { 'rpcstatus' : 'ok',
                  'type'      : <wiki type string>
                  'summary'   : <wiki summary string>
                  'sourceurl' : <source url to be interpreted based on wiki type>
                  'text'      : <wiki text string>
                }
            On failure,
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                }
        """
        from zeta.config.environment    import xicomp

        wikiurl = unicode(self.url_wikiurl( projectname, self._stripurl( pagename) ))
        if res :
            return res
        else :
            res = self._permissions(
                        c.authuser, h.authorized( h.HasPermname( 'WIKI_VIEW' ))
                  )
            rc, d, failmsg = xicomp.read_wiki( unicode(projectname), wikiurl )
            # Marshal None into 'None'
            for k in d :
                d[k] = self._marshalNone( d[k] )
            return _result( rc, d=d, failmsg=failmsg )
Пример #23
0
    def tagwiki( self, projectname, pagename, addtags, deltags ) :
        """
        === tagwiki( projectname, pagename, addtags, deltags )
       
        :Description ::
            Add or delete tags from wiki-page `pagename`, under project
            `projectname`.

        Positional arguments,
        |= projectname | a valid project-name
        |= pagename    | valid and existing wiki page-name
        |= addtags     | list of tagnames to add, if False, will be skipped
        |= deltags     | list of tagnames to delete, if False, will be skipped

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        wikiurl = unicode(self.url_wikiurl( projectname, self._stripurl( pagename) ))
        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'WIKI_CREATE' ))
              )
        if res :
            return res
        else :
            addtags, deltags = self._demarshalNone( addtags, deltags )
            addtags = addtags and [ unicode(t) for t in addtags ]
            deltags = deltags and [ unicode(t) for t in deltags ]
            rc, wiki, failmsg = xicomp.wiki_tags( unicode(projectname), wikiurl,
                                                  addtags, deltags )
            return _result( rc, failmsg=failmsg )
Пример #24
0
    def configwiki( self, projectname, pagename, wtype, summary, sourceurl ) :
        """
        === configwiki( projectname, pagename, wtype, summary, sourceurl )
        
        :Description ::
            Config wiki-page, `pagename` under project, `projectname`,

        Positional arguments,
        |= projectname | a valid project-name
        |= pagename    | valid and existing wiki page-name
        |= wtype       | type of wiki page, if False, will be skipped
        |= summary     | summary string, if False, will be skipped
        |= sourceurl   | source url, if False, will be skipped

        On success,
            [<PRE { 'rpcstatus'  : 'ok' } >]
        On failure,
            [<PRE
            { 'rpcstatus' : 'fail',
              'message'   : <msg string indicating reason for failure>
            } >]
        """
        from zeta.config.environment    import xicomp

        wikiurl = unicode(self.url_wikiurl( projectname, self._stripurl( pagename) ))
        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'WIKI_CREATE' ))
              )
        if res :
            return res
        else :
            wtype, summary, sourceurl = \
                    self._demarshalNone( wtype, summary, sourceurl )
            rc, wiki, failmsg = xicomp.config_wiki( unicode(projectname),
                                                    wikiurl, wtype, summary,
                                                    sourceurl )
            return _result( rc, failmsg=failmsg )
Пример #25
0
    def publishstaticwiki( self, path, content, swtype, sourceurl ) :
        """
        === publishstaticwiki( path, content )

        :Description ::
            Publish new content, (or updated content) onto a static wiki page,

        Positional arguments,
        |= path     | a valid and existing url-path
        |= content  | wiki text to publish

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        res = self._permissions(
                    c.authuser,
                    h.authorized( h.HasPermname( 'STATICWIKI_CREATE' ))
              )
        if res :
            return res
        else :
            path    = self._stripurl( path )
            swtype, sourceurl = self._demarshalNone( swtype, sourceurl )
            rc, sw, failmsg = xicomp.update_sw(
                                    path, unicode(content), swtype=swtype,
                                    sourceurl=sourceurl
                              )
            return _result( rc, failmsg=failmsg )
Пример #26
0
    def tagticket( self, projectname, ticket, addtags, deltags ) :
        """
        === tagticket( projectname, ticket, addtags, deltags )
        
        :Description ::
            Add or delete tags from `ticket`,

        Positional arguments,
        |= projectname | a valid project-name
        |= ticket      | a valid ticket id
        |= addtags     | list of tagnames to add, if False, will be skipped
        |= deltags     | list of tagnames to delete, if False, will be skipped

        :Return ::
            On success,
                [<PRE { 'rpcstatus'  : 'ok' } >]
            On failure,
                [<PRE
                { 'rpcstatus' : 'fail',
                  'message'   : <msg string indicating reason for failure>
                } >]
        """
        from zeta.config.environment    import xicomp

        res = self._permissions(
                    c.authuser, h.authorized( h.HasPermname( 'TICKET_CREATE' ))
              )
        if res :
            return res
        else :
            addtags, deltags = self._demarshalNone( addtags, deltags )
            addtags = addtags and [ unicode(t) for t in addtags ]
            deltags = deltags and [ unicode(t) for t in deltags ]
            rc, t, failmsg = xicomp.ticket_tags( unicode(projectname), ticket,
                                                 addtags, deltags )
            return _result( rc, failmsg=failmsg )
Пример #27
0
class ProjticketController(BaseController):
    """Class to handle project ticket page request"""
    def __before__(self, environ):
        """Called before calling any actions under this controller"""

        # Generic, app-level before-controller handler
        self.beforecontrollers(environ=environ)
        self.dourls(environ, None)
        c.metanavs = metanav(environ)
        c.mainnavs = mainnav(c.projectname, c.controllername)

        # Collect the query values into 'context'
        c.graph = request.params.get('graph', None)
        c.tree = request.params.get('tree', None)
        c.forowner = request.params.get('owner', None)
        c.forcomp = request.params.get('comp', None)
        c.formstn = request.params.get('mstn', None)
        c.forver = request.params.get('ver', None)

        c.ticket = tckcomp.get_ticket(
            c.ticket_id, attrload=['attachments', 'tags', 'type', 'severity'
                                   ]) if c.tckid else None
        c.project = projcomp.get_project(c.projectname,
                                         attrload=[
                                             'logofile',
                                         ]) if c.projectname else None
        c.prjlogo = c.project and c.project.logofile and \
                    self.url_attach( c.project.logofile.id )

        c.searchfaces = [('project', c.projectname), ('ticket', '1')]

    def formpermission(self):
        return (c.form == 'submit') and (c.formname in tckperm) and (
            not h.authorized(tckperm[c.formname]))

    def _seltickets(self):
        p = c.projectname
        fn = lambda tckid: [self.url_ticket(p, tckid), str(tckid)]
        return map(fn, tckcomp.ticketids(c.project))

    def _ticketattachs(self, ticket):
        """For JSON consumption.
        Massage the ticket attachments"""
        return self.modelattachments(ticket)

    def _tickettags(self, ticket):
        """For JSON consumption.
        Massage the ticket tags"""
        return self.modeltags(ticket)

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def _json_ticketlist(self):  # JSON-GRID
        """Fetch the json object with caching, under `projectname`
       JSON: { id   : 'id',
               label: 'ticket_id',
               items: [ { id             : tck.id,
                          projectname    : tck.project.projectname,
                          ts_id          : ts.id ,
                          ticketurl      : url_for(ticket) ,
                          summary        : tck.summary,
                          tck_typename   : tck.type.typename,
                          tck_severityname : tck.severity.tck_severityname,
                          tck_statusname : tck.status.tck_statusname,
                          due_date       : ts.due_date ,
                          owner          : ts.owner.username,
                          promptuser     : tck.promptuser.username,
                          component_id   : component.id,
                          componentname  : component.componentname,
                          milestone_id   : milestone.id,
                          milestone_name : milestone.milestone_name,
                          version_id     : version.id,,
                          version_name   : version.version_name,
                          upvotes        : upvotes ,
                          downvotes      : downvotes,
                          age            : age          },
                        ... ]
             }"""
        from zeta.config.environment import tckcomp

        def format_item(tup):
            due_date = tup[8].astimezone(h.timezone(
                c.authuser.timezone)) if tup[8] else None
            ymd = [due_date.year, due_date.month, due_date.day
                   ] if due_date else []
            age = h.olderby(dt.datetime.utcnow().toordinal() -
                            tup[3].toordinal())
            d = {
                'id': tup[0],
                'projectname': tup[1],
                'ticketurl': self.url_ticket(c.project.projectname, tup[0]),
                'summary': tup[2],
                'tck_typename': tup[4],
                'tck_severityname': tup[5],
                'tck_statusname': tup[6],
                'ts_id': tup[7],
                'due_date': ymd,
                'owner': tup[9],
                'promptuser': tup[10],
                'component_id': tup[11],
                'componentname': tup[12],
                'milestone_id': tup[13],
                'milestone_name': tup[14],
                'version_id': tup[15],
                'version_name': tup[16],
                'upvotes': tup[17],
                'downvotes': tup[18],
                'age': age,
            }
            d = tckcomp.computefilters(d, tckfilters=c.tckfilters)[0]
            return (d.get(c.stdfilter, True) and d) if c.stdfilter else d

        c.tckfilters = h.compile_tckfilters(tckfilters)
        savfilters = dict([(tf.id, h.json.loads(tf.filterbyjson))
                           for tf in tckcomp.get_ticketfilter(user=c.authuser)
                           ])
        filters = savfilters.get(c.savfilter, {})
        tcklist = tckcomp.ticketlist(project=c.project, filters=filters)
        tcklist = sorted(tcklist.values(), key=lambda l: l[0], reverse=True)
        _tl = h.todojoreadstore(tcklist,
                                format_item,
                                id='id',
                                label='ticket_id')
        return _tl

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def _json_tckattachs(self):  # JSON
        """JSON: { id : [ id, url, filename, summary ], ... } """
        return json.dumps(self._ticketattachs(c.ticket))

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def _json_tcktags(self):  # JSON
        """JSON: { tagname : tagname ... } """
        return json.dumps(self._tickettags(c.ticket))

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def _json_tckcomments(self):  # JSON
        """JSON: { id : 'ticket_comment_id',
                   label : 'ticket_comment_id',
                   items: [ { ticket_comment_id : tcmt.id,
                              commentby         : tcmt.commentby.username,
                              text              : tcmt.text,
                              html              : tcmt.texthtml,
                              commentbyicon     : usericon,
                              commentbyurl      : userurl,
                              datestr           : tcmt.created_on },
                            ... ]
                 }"""
        from zeta.config.environment import tckcomp

        def format_item(qres):
            d = {
                'ticket_comment_id':
                qres[0],
                'commentby':
                qres[4],
                'text':
                qres[1],
                'html':
                qres[2],
                'commentbyicon':
                '',
                'commentbyurl':
                self.url_user(qres[4]),
                'datestr':
                h.utc_2_usertz(qres[3],
                               c.authuser.timezone).strftime('%d %b %Y, %r'),
            }
            return d

        return h.todojoreadstore(tckcomp.tckcomments(c.ticket.id),
                                 format_item,
                                 id='ticket_comment_id',
                                 label='ticket_comment_id')

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def _json_tckrcomments(self):  # JSON
        """JSON: { id : 'ticket_comment_id',
                   label: 'ticket_comment_id',
                   items: [ { ticket_comment_id : tcmt.id,
                              commentby         : tcmt.commentby.username ,
                              text              : tcmt.text,
                              html              : tcmt.texthtml,
                              commentbyicon     : usericon,
                              commentbyurl      : userurl,
                              datestr           : tcmt.created_on },
                            ... ]
                 }"""
        from zeta.config.environment import tckcomp

        def format_item(qres):
            d = {
                'ticket_comment_id':
                qres[0],
                'commentby':
                qres[4],
                'text':
                qres[1],
                'html':
                qres[2],
                'commentbyicon':
                '',
                'commentbyurl':
                self.url_user(qres[4]),
                'datestr':
                h.utc_2_usertz(qres[3],
                               c.authuser.timezone).strftime('%d %b %Y, %r'),
            }
            return d

        tcomments = tckcomp.tckrcomments(c.ticket.id)
        items = []
        while tcomments:
            tcomment = tcomments.pop(0)
            d_tcmt = format_item(tcomment)
            d_tcmt.setdefault(
                'replies',
                [format_item(rtcomment) for rtcomment in tcomment[-1]])
            items.append(d_tcmt)

        return h.todojoreadstore(items,
                                 lambda v: v,
                                 id='ticket_comment_id',
                                 label='ticket_comment_id')

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def ticketindex(self, environ, projectname):
        """Project tickets
        URLS :
            /p/{projectname}/t
            /p/{projectname}/t?stdfilter=<stdfilter>&savfilter=<savfilter>
            /p/{projectname}/t?jsonobj=ticketlist&view=js
            /p/{projectname}/t?form=submit&formname=configtck&view=js
            /p/{projectname}/t?form=submit&formname=configtstat&view=js
            /p/{projectname}/t?form=submit&formname=addtckfilter&view=js
            /p/{projectname}/t?form=submit&formname=deltckfilter&view=js
        """
        from zeta.config.environment import vfcomp, projcomp, tckcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        if self.formpermission():
            c.errmsg = 'Do not have %s permission !!' % tckperm[c.formname]
        else:
            vfcomp.process(request,
                           c,
                           defer=True,
                           errhandler=h.hitchfn(errhandler),
                           formnames=[
                               'configtck', 'configtstat', 'addtckfilter',
                               'deltckfilter'
                           ],
                           user=c.authuser)

        # Setup context for both html page and AJAX request.
        c.projsummary = c.project.summary
        c.tckfilters = h.compile_tckfilters(tckfilters)
        c.title = '-Skip-'

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)
        elif c.view == 'js' and c.jsonobj:
            html = self.handlejson(environ)

        elif c.view != 'js' and not (c.stdfilter
                                     or c.savfilter) and c.tckfilters:
            url = self.url_tcklist(projectname, stdfilter=c.tckfilters[0][0])
            h.redirect_url(url)

        elif c.view != 'js':
            # Setup context for html page
            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames
            c.seltickets = self._seltickets()

            c.pcomponents, c.pmilestones, c.pversions, c.projusers = \
                              tckcomp.projdetails( c.project )
            c.projusers = self.projusers(c.project)
            c.pmilestones = [m[:2] for m in c.pmilestones if not any(m[2:])]
            c.mstnnames = sorted([m[0] for m in c.pmilestones])
            c.pcompnames = sorted([comp[0] for comp in c.pcomponents])
            c.vernames = sorted([ver[0] for ver in c.pversions])
            c.tckeditable = h.authorized(h.HasPermname('TICKET_CREATE'))
            c.tckccodes = h.tckccodes
            c.tstat_resolv = h.parse_csv(c.sysentries.get(u'ticketresolv', ''))
            userfilters = tckcomp.get_ticketfilter(user=c.authuser)
            fn = lambda tf: (tf.id, [tf.name, tf.filterbyjson])
            c.savfilterlist = dict(map(fn, userfilters))
            c.savfilterval = c.savfilterlist.get(c.savfilter, ['', ''])
            c.savfiltername = c.savfilterval[0]
            fn = lambda k, v: [
                self.url_tcklist(c.projectname, savfilter=k), v[0]
            ]
            c.savfilterlist = map(fn, c.savfilterlist.iteritems())
            c.title = 'Ticket:list'
            html = render('/derived/projects/ticketindex.html')

        c.rclose.append(html)
        return c.rclose

    @h.authorize(h.HasPermname('TICKET_CREATE'))
    def createticket(self, environ, projectname):
        """Create ticket
        URLS :
            /p/{projectname}/t/createticket?form=request&formname=createtck
            /p/{projectname}/t/createticket?form=submit&formname=createtck
        """
        from zeta.config.environment import vfcomp, projcomp, tckcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        vfcomp.process(request,
                       c,
                       defer=True,
                       errhandler=h.hitchfn(errhandler),
                       formnames=['createtck'],
                       user=c.authuser)

        # Setup context for page generation
        c.project = c.project or projcomp.get_project(projectname)
        c.projectname = c.project.projectname
        c.projsummary = c.project.summary

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)

        elif c.form == 'submit':
            h.flash(MESSAGE_FLASH + 'Created ticket ...')
            # Ticket creation, redirect after submit
            c.title = '-Skip-'
            h.redirect_url(h.url_ticketcreate)

        else:
            # Setup context for page generation
            c.seltickets = self._seltickets()
            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames

            c.pcomponents, c.pmilestones, c.pversions, c.projusers = \
                              tckcomp.projdetails( c.project )
            c.projusers = list(set(c.projusers + [c.project.admin.username]))
            c.pmilestones = [m[:2] for m in c.pmilestones if not any(m[2:])]
            c.mstnnames = sorted([m[0] for m in c.pmilestones])

            c.pcompnames = sorted([comp[0] for comp in c.pcomponents])
            c.vernames = sorted([ver[0] for ver in c.pversions])
            c.pcomponents = [(tup[1], tup[0]) for tup in c.pcomponents]
            c.pmilestones = [(tup[1], tup[0]) for tup in c.pmilestones]
            c.pversions = [(tup[1], tup[0]) for tup in c.pversions]
            c.title = 'CreateTicket'
            c.tckeditable = h.authorized(h.HasPermname('TICKET_CREATE'))
            html = render('/derived/projects/ticketcreate.html')
            h.flash.pop_messages(
            )  # Clear flashmessage if any ! after page generation

        c.rclose.append(html)
        return c.rclose

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def ticket(self, environ, projectname, tckid):
        """Each ticket
        URLS : 
            /p/{projectname}/t/{tckid}
            /p/{projectname}/t/{tckid}?jsonobj=tckattachs&view=js
            /p/{projectname}/t/{tckid}?jsonobj=tcktags&view=js
            /p/{projectname}/t/{tckid}?jsonobj=tckcomments&view=js
            /p/{projectname}/t/{tckid}?jsonobj=tckrcomments&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=createtstat&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=addtckattachs&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=deltckattachs&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=addtcktags&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=deltcktags&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=createtcmt&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=updatetcmt&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=replytcmt&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=tckfav&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=votetck&view=js
        """
        from zeta.config.environment import vfcomp, projcomp, tckcomp, votcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        if self.formpermission():
            c.errmsg = 'Do not have %s permission !!' % tckperm[c.formname]
        else:
            vfcomp.process(request,
                           c,
                           defer=True,
                           errhandler=h.hitchfn(errhandler),
                           formnames=[
                               'createtstat', 'addtckattachs', 'deltckattachs',
                               'addtcktags', 'deltcktags', 'createtcmt',
                               'updatetcmt', 'replytcmt', 'tckfav', 'votetck'
                           ],
                           user=c.authuser)

        # Setup context for page generation
        c.projsummary = c.project.summary
        if not c.jsonobj:
            c.tckeditable = c.att_editable = c.tag_editable = h.authorized(
                h.HasPermname('TICKET_CREATE'))
            c.seltickets = self._seltickets()
            c.tckccodes = h.tckccodes
            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames
            c.pcomponents, c.pmilestones, c.pversions, c.projusers = \
                              tckcomp.projdetails( c.project )
            c.pmilestones = [m[:2] for m in c.pmilestones if not any(m[2:])]
            c.pcomponents = [(tup[1], tup[0]) for tup in c.pcomponents]
            c.pmilestones = [(tup[1], tup[0]) for tup in c.pmilestones]
            c.pversions = [(tup[1], tup[0]) for tup in c.pversions]
            c.items_tckcomments = self._json_tckcomments()
            c.attachs = self._ticketattachs(c.ticket)
            c.tags = self._tickettags(c.ticket)
            c.isuserfavorite = tckcomp.isfavorite(c.authuser.id, c.ticket.id)
            c.ticketdetail = tckcomp.ticketdetails(c.ticket)
            c.ticketstatus = tckcomp.ticketstatus(c.ticket)
            c.blockers = tckcomp.blockersof(c.ticket)
            c.blocking = tckcomp.blockingfor(c.ticket)
            c.children = tckcomp.childrenfor(c.ticket)
            c.ticketresolv = h.parse_csv(c.sysentries.get('ticketresolv', ''))
            c.title = 'Ticket:%s' % tckid

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)

        elif c.view == 'js' and c.formname in ['addtckattachs']:
            html = IFRAME_RET

        elif c.jsonobj and c.view == 'js':
            html = self.handlejson(environ)

        elif c.textobj and c.view == 'text':
            html = self.handletext(environ)

        elif c.view != 'js':
            uservote = votcomp.get_ticketvote(c.authuser, c.ticket)
            votes = tckcomp.countvotes(ticket=c.ticket)
            c.upvotes = votes.get('up', 0)
            c.downvotes = votes.get('down', 0)
            c.currvote = uservote and uservote.votedas or ''
            html = render('/derived/projects/ticket.html')
        else:
            html = ''

        c.rclose.append(html)
        return c.rclose

    @h.authorize(h.HasPermname('TICKET_VIEW'))
    def ticketgraph(self, environ, projectname, tckid, file):
        """Each ticket
        URLS :
            /p/{projectname}/t/{tckid}/{graph.svg}
            /p/{projectname}/t/{tckid}/{tree.svg}
        """
        from zeta.config.environment import tckcomp

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.tckccodes = h.tckccodes

        # HTML page generation
        if file == 'graph.svg':  # Dependency graph
            x = tckcomp.allblockers()
            y = tckcomp.ticketdeps()
            tckdeps = gviz.calctckdep(x, y)
            z = gviz.tckdeptodot(c.ticket.id, tckdeps, c.tckccodes)
            html = gviz.tosvgtext(z)
            response.content_type = 'image/svg+xml'

        elif file == 'tree.svg':  # Hierarchy graph
            x = tckcomp.allparchild()
            y = tckcomp.ticketdeps()
            tckhier = gviz.calctckhier(x, y)
            z = gviz.tckhiertodot(c.ticket.id, tckhier, c.tckccodes)
            html = gviz.tosvgtext(z)
            response.content_type = 'image/svg+xml'

        if file == 'graph.png':  # Dependency graph
            x = tckcomp.allblockers()
            y = tckcomp.ticketdeps()
            tckdeps = gviz.calctckdep(x, y)
            z = gviz.tckdeptodot(c.ticket.id, tckdeps, c.tckccodes)
            html = gviz.topng(z)
            response.content_type = 'image/png'

        elif file == 'tree.png':  # Hierarchy graph
            x = tckcomp.allparchild()
            y = tckcomp.ticketdeps()
            tckhier = gviz.calctckhier(x, y)
            z = gviz.tckhiertodot(c.ticket.id, tckhier, c.tckccodes)
            html = gviz.topng(z)
            response.content_type = 'image/png'
        else:
            html = ''

        c.rclose.append(html)
        return c.rclose

    @h.authorize(h.HasPermname(['TICKET_VIEW']))
    def timelines(self, environ, projectname):
        """Activities under project tickets or individual ticket
        URLS :
            /p/{projectname}/t/timeline
        """
        from zeta.config.environment import projcomp, tckcomp

        c.rclose = h.ZResp()

        logid = request.params.get('logid', None)
        dir = request.params.get('dir', None)
        fromoff = request.params.get('fromoff', 1)
        logid = logid and int(logid)
        fromoff = int(fromoff)

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.seltickets = self._seltickets()
        routeargs = {'projectname': projectname}
        self.tline_controller(h.r_projtckstline, routeargs,
                              ['ticket', 'project'], fromoff, logid, dir,
                              c.project)
        c.title = 'Tickets:timeline'

        c.datatline, c.startdt = h.tlineplot(c.logs[:])
        c.rclose.append(render('/derived/projects/tickettline.html'))
        return c.rclose

    @h.authorize(h.HasPermname(['TICKET_VIEW']))
    def timeline(self, environ, projectname, tckid):
        """Activities under project tickets or individual ticket
        URLS :
            /p/{projectname}/t/timeline/{tckid}
        """
        from zeta.config.environment import projcomp, tckcomp

        c.rclose = h.ZResp()

        logid = request.params.get('logid', None)
        dir = request.params.get('dir', None)
        fromoff = request.params.get('fromoff', 1)
        logid = logid and int(logid)
        fromoff = int(fromoff)

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.seltickets = self._seltickets()
        routeargs = {'projectname': projectname, 'tckid': tckid}
        self.tline_controller(h.r_projtcktline, routeargs, 'ticket', fromoff,
                              logid, dir, c.ticket)
        c.title = 'Ticket:%s:timeline' % tckid
        c.datatline, c.startdt = h.tlineplot(c.logs[:])

        c.rclose.append(render('/derived/projects/tickettline.html'))
        return c.rclose

    def feeds(self, environ, projectname):
        """Activities under project tickets or individual ticket
        URLS :
            /p/{projectname}/t/feed
        """
        from zeta.config.environment import projcomp, tckcomp

        # Setup context for page generation
        title = '%s:tickets' % projectname
        link = h.urlroot(environ)
        descr = 'Timeline for tickets in project %s' % projectname
        c.projsummary = c.project.summary
        feed = h.FeedGen(title, link, descr)
        routeargs = {'projectname': projectname}
        self.tline_controller(h.r_projtckstline, routeargs,
                              ['ticket', 'project'], 1, None, None, c.project)
        feedhtml = self.feeds(environ, link, feed, c.logs)
        response.content_type = 'application/atom+xml'
        return feedhtml

    def feed(self, environ, projectname, tckid):
        """Activities under project tickets or individual ticket
        URLS :
            /p/{projectname}/t/feed/{tckid}
        """
        from zeta.config.environment import projcomp, tckcomp

        # Setup context for page generation
        title = '%s-ticket:(%s)' % (projectname, tckid)
        link = h.urlroot(environ)
        descr = 'Timeline for ticket %s in project %s' % (tckid, projectname)
        c.projsummary = c.project.summary
        feed = h.FeedGen(title, link, descr)
        routeargs = {'projectname': projectname, 'tckid': tckid}
        self.tline_controller(h.r_projtcktline, routeargs, 'ticket', 1, None,
                              None, c.ticket)
        feedhtml = self.feeds(environ, link, feed, c.logs)
        response.content_type = 'application/atom+xml'
        return feedhtml

    _charts = {
        'chart21': 'project-tickets',
        'chart22': 'ticket-owners',
        'chart23': 'ticket-components',
        'chart24': 'ticket-milestones',
        'chart25': 'ticket-versions',
        'chart26': 'ticket-commenters',
    }

    @h.authorize(h.HasPermname(['TICKET_VIEW']))
    def charts(self, environ, projectname):
        """Charts and analytics for project tickets
        URLS : 
            /p/{projectname}/t/charts
            /p/{projectname}/t/charts?chartname=<name>
        """

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.chartname = c.chartname or 'chart21'
        c.selectedchart = (c.chartname, self._charts[c.chartname])
        fn = lambda n, t: (self.url_tckchart(projectname, n), t)
        c.chartoptions = map(fn, self._charts.iteritems())
        c.tcka = ca.get_analyticobj('tickets')

        if c.chartname == 'chart21':
            # Pie chart for types, severity and status
            c.chart21_data = getattr(c.tcka, 'chart21_data',
                                     {}).get(c.project.id, [])

        elif c.chartname == 'chart22':
            # Pie chart of types, severity and status for project users
            allusers = getattr(c.tcka, 'chart22_data',
                               {}).get(c.project.id, [])
            c.chart22_usrs = getattr(c.tcka, 'chart22_usrs',
                                     {}).get(c.project.id, [])
            p = c.projectname
            fn = lambda u: (self.url_tckchart(p, 'chart22', owner=u[0]), u[0])
            c.ticketowners = map(fn, c.chart22_usrs)
            c.forowner = c.forowner or (c.chart22_usrs and c.chart22_usrs[0][0])\
                         or ''
            c.selectedowner = c.forowner

            # Fetch chart data for requested user (owner)
            for u in allusers:
                if u[0] == c.forowner:
                    c.chart22_data = u[1:]
                    break
            else:
                c.chart22_data = []

        elif c.chartname == 'chart23':
            # Pie chart of types, severity and status for project components
            allcomps = getattr(c.tcka, 'chart23_data',
                               {}).get(c.project.id, [])
            componentnames = sorted(map(lambda x: x[0], allcomps))
            p = c.projectname
            fn = lambda comp: (self.url_tckchart(p, 'chart23', comp=comp), comp
                               )
            c.ticketcomps = map(fn, componentnames)
            c.forcomp = c.forcomp or (componentnames
                                      and componentnames[0]) or ''
            c.selectedcomp = c.forcomp

            # Fetch chart data for requested component
            for comp in allcomps:
                if comp[0] == c.forcomp:
                    c.chart23_data = comp[1:]
                    break
            else:
                c.chart23_data = []

        elif c.chartname == 'chart24':
            # Pie chart of types, severity and status for project milestones
            allmstns = getattr(c.tcka, 'chart24_data',
                               {}).get(c.project.id, [])
            milestonenames = sorted(map(lambda x: x[0], allmstns))
            p = c.projectname
            fn = lambda m: (self.url_tckchart(p, 'chart24', mstn=m), m)
            c.ticketmstns = map(fn, milestonenames)
            c.formstn = c.formstn or (milestonenames
                                      and milestonenames[0]) or ''
            c.selectedmstn = c.formstn

            # Fetch chart data for requested milestone
            for mstn in allmstns:
                if mstn[0] == c.formstn:
                    c.chart24_data = mstn[1:]
                    break
            else:
                c.chart24_data = []

        elif c.chartname == 'chart25':
            # Pie chart of types, severity and status for project versions
            allvers = getattr(c.tcka, 'chart25_data', {}).get(c.project.id, [])
            versionnames = sorted(map(lambda x: x[0], allvers))
            p = c.projectname
            fn = lambda v: (self.url_tckchart(p, 'chart25', ver=v), v)
            c.ticketvers = map(fn, versionnames)
            c.forver = c.forver or (versionnames and versionnames[0]) or ''
            c.selectedver = c.forver

            # Fetch chart data for requested milestone
            for ver in allvers:
                if ver[0] == c.forver:
                    c.chart25_data = ver[1:]
                    break
            else:
                c.chart25_data = []

        elif c.chartname == 'chart26':
            # Ticket commentors
            c.chart26_data = getattr(c.tcka, 'chart26_data',
                                     {}).get(c.project.id, [])
            c.chart26_usrs = getattr(c.tcka, 'chart26_usrs',
                                     {}).get(c.project.id, [])

        c.title = 'TicketCharts'
        c.rclose.append(render('/derived/projects/ticketcharts.html'))
        return c.rclose

    @h.authorize(h.HasPermname(['TICKET_VIEW']))
    def attachs(self, environ, projectname):
        """Action to present attachment page for tickets under project 
        `projectname`
        URLS :
            /p/{projectname}/t/attachs
        """
        from zeta.config.environment import vfcomp, tckcomp

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        attachments = tckcomp.attachments(c.project)
        c.attachments = self.attachments(attachments)
        c.editable = h.authorized(h.HasPermname('TICKET_CREATE'))
        c.title = 'TicketAttachs'
        c.rclose.append(render('/derived/projects/tckattachs.html'))
        return c.rclose

    def __after__(self):
        """Called calling any actions under this controller"""
        self.aftercontrollers()
Пример #28
0
    def ticket(self, environ, projectname, tckid):
        """Each ticket
        URLS : 
            /p/{projectname}/t/{tckid}
            /p/{projectname}/t/{tckid}?jsonobj=tckattachs&view=js
            /p/{projectname}/t/{tckid}?jsonobj=tcktags&view=js
            /p/{projectname}/t/{tckid}?jsonobj=tckcomments&view=js
            /p/{projectname}/t/{tckid}?jsonobj=tckrcomments&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=createtstat&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=addtckattachs&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=deltckattachs&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=addtcktags&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=deltcktags&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=createtcmt&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=updatetcmt&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=replytcmt&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=tckfav&view=js
            /p/{projectname}/t/{tckid}?form=submit&formname=votetck&view=js
        """
        from zeta.config.environment import vfcomp, projcomp, tckcomp, votcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        if self.formpermission():
            c.errmsg = 'Do not have %s permission !!' % tckperm[c.formname]
        else:
            vfcomp.process(request,
                           c,
                           defer=True,
                           errhandler=h.hitchfn(errhandler),
                           formnames=[
                               'createtstat', 'addtckattachs', 'deltckattachs',
                               'addtcktags', 'deltcktags', 'createtcmt',
                               'updatetcmt', 'replytcmt', 'tckfav', 'votetck'
                           ],
                           user=c.authuser)

        # Setup context for page generation
        c.projsummary = c.project.summary
        if not c.jsonobj:
            c.tckeditable = c.att_editable = c.tag_editable = h.authorized(
                h.HasPermname('TICKET_CREATE'))
            c.seltickets = self._seltickets()
            c.tckccodes = h.tckccodes
            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames
            c.pcomponents, c.pmilestones, c.pversions, c.projusers = \
                              tckcomp.projdetails( c.project )
            c.pmilestones = [m[:2] for m in c.pmilestones if not any(m[2:])]
            c.pcomponents = [(tup[1], tup[0]) for tup in c.pcomponents]
            c.pmilestones = [(tup[1], tup[0]) for tup in c.pmilestones]
            c.pversions = [(tup[1], tup[0]) for tup in c.pversions]
            c.items_tckcomments = self._json_tckcomments()
            c.attachs = self._ticketattachs(c.ticket)
            c.tags = self._tickettags(c.ticket)
            c.isuserfavorite = tckcomp.isfavorite(c.authuser.id, c.ticket.id)
            c.ticketdetail = tckcomp.ticketdetails(c.ticket)
            c.ticketstatus = tckcomp.ticketstatus(c.ticket)
            c.blockers = tckcomp.blockersof(c.ticket)
            c.blocking = tckcomp.blockingfor(c.ticket)
            c.children = tckcomp.childrenfor(c.ticket)
            c.ticketresolv = h.parse_csv(c.sysentries.get('ticketresolv', ''))
            c.title = 'Ticket:%s' % tckid

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)

        elif c.view == 'js' and c.formname in ['addtckattachs']:
            html = IFRAME_RET

        elif c.jsonobj and c.view == 'js':
            html = self.handlejson(environ)

        elif c.textobj and c.view == 'text':
            html = self.handletext(environ)

        elif c.view != 'js':
            uservote = votcomp.get_ticketvote(c.authuser, c.ticket)
            votes = tckcomp.countvotes(ticket=c.ticket)
            c.upvotes = votes.get('up', 0)
            c.downvotes = votes.get('down', 0)
            c.currvote = uservote and uservote.votedas or ''
            html = render('/derived/projects/ticket.html')
        else:
            html = ''

        c.rclose.append(html)
        return c.rclose
Пример #29
0
    def createticket(self, environ, projectname):
        """Create ticket
        URLS :
            /p/{projectname}/t/createticket?form=request&formname=createtck
            /p/{projectname}/t/createticket?form=submit&formname=createtck
        """
        from zeta.config.environment import vfcomp, projcomp, tckcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        vfcomp.process(request,
                       c,
                       defer=True,
                       errhandler=h.hitchfn(errhandler),
                       formnames=['createtck'],
                       user=c.authuser)

        # Setup context for page generation
        c.project = c.project or projcomp.get_project(projectname)
        c.projectname = c.project.projectname
        c.projsummary = c.project.summary

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)

        elif c.form == 'submit':
            h.flash(MESSAGE_FLASH + 'Created ticket ...')
            # Ticket creation, redirect after submit
            c.title = '-Skip-'
            h.redirect_url(h.url_ticketcreate)

        else:
            # Setup context for page generation
            c.seltickets = self._seltickets()
            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames

            c.pcomponents, c.pmilestones, c.pversions, c.projusers = \
                              tckcomp.projdetails( c.project )
            c.projusers = list(set(c.projusers + [c.project.admin.username]))
            c.pmilestones = [m[:2] for m in c.pmilestones if not any(m[2:])]
            c.mstnnames = sorted([m[0] for m in c.pmilestones])

            c.pcompnames = sorted([comp[0] for comp in c.pcomponents])
            c.vernames = sorted([ver[0] for ver in c.pversions])
            c.pcomponents = [(tup[1], tup[0]) for tup in c.pcomponents]
            c.pmilestones = [(tup[1], tup[0]) for tup in c.pmilestones]
            c.pversions = [(tup[1], tup[0]) for tup in c.pversions]
            c.title = 'CreateTicket'
            c.tckeditable = h.authorized(h.HasPermname('TICKET_CREATE'))
            html = render('/derived/projects/ticketcreate.html')
            h.flash.pop_messages(
            )  # Clear flashmessage if any ! after page generation

        c.rclose.append(html)
        return c.rclose
Пример #30
0
    def ticketindex(self, environ, projectname):
        """Project tickets
        URLS :
            /p/{projectname}/t
            /p/{projectname}/t?stdfilter=<stdfilter>&savfilter=<savfilter>
            /p/{projectname}/t?jsonobj=ticketlist&view=js
            /p/{projectname}/t?form=submit&formname=configtck&view=js
            /p/{projectname}/t?form=submit&formname=configtstat&view=js
            /p/{projectname}/t?form=submit&formname=addtckfilter&view=js
            /p/{projectname}/t?form=submit&formname=deltckfilter&view=js
        """
        from zeta.config.environment import vfcomp, projcomp, tckcomp

        c.rclose = h.ZResp()

        # Handle forms
        def errhandler(errmsg):
            c.errmsg = errmsg

        if self.formpermission():
            c.errmsg = 'Do not have %s permission !!' % tckperm[c.formname]
        else:
            vfcomp.process(request,
                           c,
                           defer=True,
                           errhandler=h.hitchfn(errhandler),
                           formnames=[
                               'configtck', 'configtstat', 'addtckfilter',
                               'deltckfilter'
                           ],
                           user=c.authuser)

        # Setup context for both html page and AJAX request.
        c.projsummary = c.project.summary
        c.tckfilters = h.compile_tckfilters(tckfilters)
        c.title = '-Skip-'

        # HTML page generation
        if c.errmsg:
            html = self.returnerrmsg(environ)
        elif c.view == 'js' and c.jsonobj:
            html = self.handlejson(environ)

        elif c.view != 'js' and not (c.stdfilter
                                     or c.savfilter) and c.tckfilters:
            url = self.url_tcklist(projectname, stdfilter=c.tckfilters[0][0])
            h.redirect_url(url)

        elif c.view != 'js':
            # Setup context for html page
            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames
            c.seltickets = self._seltickets()

            c.pcomponents, c.pmilestones, c.pversions, c.projusers = \
                              tckcomp.projdetails( c.project )
            c.projusers = self.projusers(c.project)
            c.pmilestones = [m[:2] for m in c.pmilestones if not any(m[2:])]
            c.mstnnames = sorted([m[0] for m in c.pmilestones])
            c.pcompnames = sorted([comp[0] for comp in c.pcomponents])
            c.vernames = sorted([ver[0] for ver in c.pversions])
            c.tckeditable = h.authorized(h.HasPermname('TICKET_CREATE'))
            c.tckccodes = h.tckccodes
            c.tstat_resolv = h.parse_csv(c.sysentries.get(u'ticketresolv', ''))
            userfilters = tckcomp.get_ticketfilter(user=c.authuser)
            fn = lambda tf: (tf.id, [tf.name, tf.filterbyjson])
            c.savfilterlist = dict(map(fn, userfilters))
            c.savfilterval = c.savfilterlist.get(c.savfilter, ['', ''])
            c.savfiltername = c.savfilterval[0]
            fn = lambda k, v: [
                self.url_tcklist(c.projectname, savfilter=k), v[0]
            ]
            c.savfilterlist = map(fn, c.savfilterlist.iteritems())
            c.title = 'Ticket:list'
            html = render('/derived/projects/ticketindex.html')

        c.rclose.append(html)
        return c.rclose