Beispiel #1
0
    def index( self, environ ) :
        """List of all attachments
        URLS :
            /attachment
            /attachment?fromid=<number>
            /attachment?all=1
            /attachment?form=submit&formname=attachssummary&view=js
            /attachment?form=submit&formname=attachstags&view=js
        """
        from zeta.config.environment    import attcomp, vfcomp

        c.rclose = h.ZResp()
        h.url_attachpages = self.url_attachpages()

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

        try :
            fromid = c.fromid and int(c.fromid)
            fromid -= 1
        except :
            fromid = None
        c.title = 'Attachments'
        c.aa = ca.get_analyticobj( 'attachs' )
        c.ua = ca.get_analyticobj( 'users' )
        c.la = ca.get_analyticobj( 'license' )
        c.pa = ca.get_analyticobj( 'projects' )
        c.ta = ca.get_analyticobj( 'tickets' )
        c.ra = ca.get_analyticobj( 'reviews' )
        c.wa = ca.get_analyticobj( 'wiki' )

        # Html page generation
        if c.errmsg :
            html = self.returnerrmsg(environ)
        elif c.view == 'js' :
            html = ''
        else :
            limit = 100 if c.all == None else None
            attachments = attcomp.attachments( offset=fromid, limit=limit )
            attachs = [ [ aid ] + attachments[aid][:-1] + \
                        [ ', '.join(attachments[aid][-1]) ] + \
                        [ self.url_attachdownl( aid ) ]
                        for aid in attachments ]
            c.attachassc= attcomp.attachassc()
            c.attachments = { 'all-attachments' : attachs }
            c.editable = h.authorized( h.ValidUser( strict='True' ))

            html = render( '/derived/attachs/index.html' )

        c.rclose.append( html )
        return c.rclose
Beispiel #2
0
    def preference( self, environ, username, **kwargs ) :
        """Handle user preference
        URLS :
            /u/{username}/preference?form=request
            /u/{username}/preference?form=submit&formname=updateuser&view=js
            /u/{username}/preference?form=submit&formname=updtpass&view=js
            /u/{username}/preference?form=submit&formname=userphoto&view=js
            /u/{username}/preference?form=submit&formname=deluserphoto&view=js
            /u/{username}/preference?form=submit&formname=usericon&view=js
            /u/{username}/preference?form=submit&formname=delusericon&view=js
            /u/{username}/preference?form=submit&formname=adduserrels&view=js
            /u/{username}/preference?form=submit&formname=approveuserrels&view=js
            /u/{username}/preference?form=submit&formname=deluserrels&view=js
        """
        from zeta.config.environment    import vfcomp

        c.rclose = h.ZResp()

        # Form handling
        def errhandler(errmsg) :
            c.errmsg = errmsg
        if c.usercaninvite :
            vfcomp.process(
                request, c, defer=True, errhandler=h.hitchfn(errhandler),
                formnames=[ 'updateuser', 'updtpass', 'userphoto',
                'deluserphoto', 'usericon', 'delusericon', 'adduserrels',
                'approveuserrels', 'deluserrels' ], user=c.authuser
            )

        # Setup context for page rendering
        uinfo            = c.authuser.userinfo
        c.title          = 'Preference'
        c.photo_editable = c.icon_editable = h.authorized( h.ValidUser( strict='True' ))
        c.photoattach    = self._userphoto( c.authuser )
        c.iconattach     = self._usericon( c.authuser )
        c.googlemaps     = h.gmapkey( c.sysentries )
        c.fulladdress    = h.useraddress( uinfo )

        # Html page generation
        if c.view == 'js' and c.formname in [ 'userphoto', 'usericon' ] :
            html = IFRAME_RET
        else :
            html = render( '/derived/userpage/preference.html' )
        c.rclose.append(html)
        return c.rclose
Beispiel #3
0
    def inviteuser( self, environ ) :
        """Invite a new user to join the site
        URLS : 
            /u/inviteuser
            /u/inviteuser?form=submit&formname=inviteuser
        """
        from zeta.config.environment    import vfcomp

        c.rclose = h.ZResp()

        # Authorize: This context attribute should be set before calling the
        # viewcontext() method.
        regrbyinvite = h.str2bool( c.sysentries['regrbyinvite'] )
        invitebyall  = h.str2bool( c.sysentries['invitebyall'] )

        c.usercaninvite = \
               ( regrbyinvite and invitebyall and \
                        h.authorized( h.ValidUser( strict='True' ))  \
               ) or \
               ( regrbyinvite and h.authorized( h.SiteAdmin() ) )

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

        c.title = 'InviteUser'

        # Html page generation
        if c.usercaninvite :
            html = render( '/derived/userpage/inviteuser.html' )
        else :
            html = render( '/derived/userpage/inviteuser.html' )
        c.rclose.append(html)
        return c.rclose
Beispiel #4
0
def metanav(environ):
    metanavs = [
        Anchor(href=h.url_projindex,
               text='projects',
               title='All hosted projects')
    ]
    if h.authorized(h.ValidUser(strict='True')):
        metanavs.extend([
            Anchor(href=None,
                   type='pointer',
                   text='quick-links',
                   title='Quick shortcut to useful links'),
            Anchor(href=None,
                   type='pointer',
                   text='myprojects',
                   title='Goto projects'),
            Anchor(href=h.url_userpref,
                   text='preference',
                   title='Your account preference'),
            Anchor(href=h.url_signout, text='signout', title='Sign out'),
        ])
    else:
        metanavs.extend([
            Anchor(href=h.url_signin,
                   text='signin',
                   title='Sign in if already registered'),
            Anchor(href=h.url_register,
                   text='register',
                   title='New User ? Sign up'),
        ])

    metanavs.extend([
        Anchor(href=h.url_aboutus, text='aboutus', title='About Us'),
        Anchor(href=h.url_helppages,
               text='help',
               title='Learn how to use ' + config['zeta.sitename']),
    ])
    return metanavs
Beispiel #5
0
class ProjectsController( BaseController ) :
    """Class to handle project page request"""

    _charts = {
        'chart14' : 'project-activity',
        'chart15' : 'roadmap',
    }

    def _optimized_fetch( self, controllername, projname ) :
        """Fetch the project object (details) from the database in an optimized
        manner based on the action and json request"""
        from zeta.config.environment    import projcomp, tckcomp

        attrload, attrload_all = ( ['logofile'], [] )
        if c.jsonobj == 'pcomplist' :
            attrload_all.extend([ 'components.owner' ])
        elif c.jsonobj == 'mstnlist' :
            attrload.extend([ 'milestones' ])
        elif c.jsonobj == 'verlist' :
            attrload.extend([ 'versions' ])
        elif controllername == 'projadmin' :
            attrload.extend([ 'iconfile', 'license', 'project_info',
                              'mailinglists', 'ircchannels', 'admin', 
                           ])
        elif controllername == 'projectmilestone' :
            attrload.extend([ 'milestones' ])
            c.mstntickets= tckcomp.mstntickets( c.project )
        elif controllername == 'projectroadmap' :
            attrload.extend([ 'milestones' ])
            c.mstntickets= tckcomp.mstntickets( c.project )
        elif controllername == 'projectcharts' :
            attrload.extend([ 'milestones', 'versions', 'components' ])
            c.mstntickets= tckcomp.mstntickets( c.project )
        elif controllername == 'projecthome' :
            attrload.extend([ 'mailinglists', 'ircchannels', 'license', 'tags',
                              'admin' ])
            attrload_all.extend([ 'team.user' ])

        c.project = projcomp.get_project(
                        projname, attrload=attrload, attrload_all=attrload_all
                    ) if projname else None

    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.id = request.params.get( 'id', None )
        c.translate = request.params.get( 'translate', False ) and True
        c.alphaindex = request.params.get( 'alphaindex', None )
        c.searchproject = [( 'project', c.projectname )]
        c.prjlogo = self.url_attach( c.project.logofile.id ) \
                    if c.project and c.project.logofile else None

        self._optimized_fetch( c.routesobj.name, c.projectname )

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

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

    def _projlogo( self, p ) :
        return self.modelattachments( p, 'logofile') if p.logofile else {}

    def _projicon( self, p ) :
        return self.modelattachments( p, 'iconfile') if p.iconfile else {}

    @h.authorize( h.ValidUser( strict='True' ))
    def _json_myprojects( self, environ ) :                          # JSON
        """JSON : { id    : ''
                    label : ''
                    item  : [ { projectnames : myprojectnames } ]
                  }"""
        fn  = lambda v : { 'projectnames': v }
        return h.todojoreadstore( [ h.myprojects(c.authuser) ], fn )

    @h.authorize( h.ValidUser() )
    def _json_projectnames( self, environ ) :                        # JSON
        """JSON : { id    : ''
                    label : ''
                    item  : [ { projectnames : projectnames } ]
                  }"""
        from zeta.config.environment    import projcomp
        fn = lambda v : { 'projectnames': v }
        return h.todojoreadstore( [ projcomp.projectnames ], fn )

    @h.authorize( h.SiteAdmin() )
    def _json_projectstatus( self, environ ) :                       # JSON
        """JSON: { id   : 'status',
                   label: 'status',
                   items: [ { status: status, projectnames: projectnames },
                            ... ]
                 }"""
        from zeta.config.environment    import projcomp
        fn = lambda k, v : { 'status' : k, 'projectnames' : v }
        return h.todojoreadstore(
                        projcomp.projectstatus, fn, id='status', label='status'
               )

    @h.authorize( h.HasPermname( ['PROJECT_VIEW'] ))
    def _json_projectlogo( self, environ ) :                         # JSON
        """JSON: { id : [ id, url, filename, summary } """
        return json.dumps( self._projlogo( c.project ) )

    @h.authorize( h.HasPermname( ['PROJECT_VIEW'] ))
    def _json_projecticon( self, environ ) :                         # JSON
        """JSON: { id : [ id, url, filename, summary } """
        return json.dumps( self._projicon( c.project ) )

    @h.authorize( h.HasPermname( 'PROJECT_VIEW' ))
    def _json_prjattach( self, environ ) :                          # JSON
        """JSON: { id : [ id, url, filename, summary ], ... } """
        return json.dumps( self._prjattachs( c.project ) )

    @h.authorize( h.HasPermname( 'PROJECT_VIEW' ))
    def _json_prjtag( self, environ ) :                             # JSON
        """JSON: { tagname : tagname, ... } """
        return json.dumps( self._prjtags( c.project ) )

    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def _json_pcomplist( self, environ ) :                           # JSON
        """JSON: { id   : 'id',
                   label: 'id',
                   items: [ { id           : component.id,
                              componentname: component.componentname,
                              owner        : component.owner 
                              description  : component.description },
                            ... ]
                 }"""
        pcomps = [ [ pcomp.id, pcomp.componentname, pcomp.owner.username,
                     pcomp.description
                   ] for pcomp in getattr( c.project, 'components', [] ) ]
        fn = lambda v : { 'id'    : v[0], 'componentname' : v[1],
                          'owner' : v[2], 'description'   : v[3],
                        }
        return h.todojoreadstore( pcomps, fn id='id', label='id' )

    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def _json_pcomptag( self, environ ) :                            # JSON
        """JSON: [ tagname, ... ] """
        from zeta.config.environment    import projcomp
        comp = projcomp.get_component( int(c.id) ) if c.id else None
        return json.dumps([ t.tagname for t in getattr( comp, 'tags', [] ) ])

    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def _json_mstnlist( self, environ ) :                            # JSON
        """JSON: { id   : 'id',
                   label: 'id',
                   items: [ { id            : milestone.id,
                              milestone_name: milestone.milestone_name,
                              due_date      : milestone.due_date ,
                              description   : milestone.description,
                              status        : milestone.status,
                              closing_remark: milestone.closing_remark },
                            ... ]
                 }"""
        mstns = []
        for mstn in getattr( c.project, 'milestones', [] ) :
            status = ( mstn.completed and 'completed' ) or \
                     ( mstn.cancelled and 'cancelled' ) or ''
            dd = []
            if mstn.due_date :
                due_date = mstn.due_date.astimezone(
                                    h.timezone( c.authuser.timezone ))
                dd = [ due_date.year, due_date.month, due_date.day ]
            mstns.append([
                mstn.id, mstn.milestone_name, dd,
                mstn.description, status, mstn.closing_remark
            ])

        fn = lambda v : { 'id'       : v[0], 'milestone_name' : v[1],
                          'due_date' : v[2], 'description'    : v[3],
                          'status'   : v[4], 'closing_remark' : v[5]
                        }
        return h.todojoreadstore( mstns, fn, id='id', label='id' )

    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def _json_mstntag( self, environ ) :                             # JSON
        """JSON: [ tagname, ... ] """
        from zeta.config.environment    import projcomp
        mstn = projcomp.get_milestone( int( c.id )) if c.id else None
        return json.dumps([ t.tagname for t in getattr( mstn, 'tags', [] ) ])

    @h.authorize( h.HasPermname( ['PROJECT_VIEW'] ))
    def _json_verlist( self, environ ) :                             # JSON
        """JSON: { id   : 'id',
                   label: 'id',
                   items: [ { id          : version.id,
                              version_name: version.version_name,
                              description : version.description },
                            ... ]
                 }"""
        vers = [ [ ver.id, ver.version_name, ver.description ]
                 for ver in getattr( c.project, 'versions', [] )
               ]
        fn = lambda v : { 'id'          : v[0], 'version_name' : v[1],
                          'description' : v[2]
                        }
        return h.todojoreadstore( vers, fn, id='id', label='id' )

    @h.authorize( h.HasPermname( ['PROJECT_VIEW'] ))
    def _json_vertag( self, environ ) :                              # JSON
        """JSON: [ tagname, ... ] """
        from zeta.config.environment    import projcomp
        ver = projcomp.get_version( int( c.id )) if c.id else None
        return json.dumps([ t.tagname for t in getattr( ver, 'tags', [] ) ])

    @h.authorize( h.ProjectAdmin() )
    def _json_projectteams( self, environ ) :               # JSON
        """JSON: { id   : 'team',
                   label: 'team',
                   items: [ { team        : team_typename,
                              usersids    : [[ pt.id, pt.user.username ], ... ],
                              x_usernames : [ username, ... ] },
                            ... ]
                 }"""
        from zeta.config.environment    import projcomp

        teams = projcomp.projectteams( project=c.project )
        teams.pop( projcomp.team_nomember )  # Prune nomember team
        fn = lambda k, v : { 'team'        : k,   'usersids' : v[0],
                             'x_usernames' : v[1]
                           }
        return h.todojoreadstore( teams, fn, id='team', label='team' )

    @h.authorize( h.ProjectAdmin() )
    def _json_teamperms( self, environ ) :                           # JSON
        """JSON: { id   : 'team',
                   label: 'team',
                   items: [ { team        : team_typename,
                              permsids    : [[ ptp.id, permgroup ] ... ],
                              x_permission: [ permission, ... ] },
                            ... ]
                 }"""
        from zeta.config.environment    import projcomp

        teamperms = projcomp.teamperms( project=c.project )
        fn = lambda k, v : { 'team'          : k,   'permsids' : v[0],
                             'x_permissions' : v[1]
                           }
        return h.todojoreadstore( teamperms, fn, id='team', label='team' )

    @h.authorize( h.ProjectAdmin() )
    def _json_prjperms( self, environ ) :                            # JSON
        """JSON: { id   : 'username',
                   label: 'username',
                   items: [ { username    : projuser,
                              permsids    : [[ pup.id, permgroup ] ... ],
                              x_permission: [ permission, ... ] },
                            ... ]
                 }"""
        from zeta.config.environment    import projcomp
        fn = lambda k, v : { 'username'      : k,   'permsids' : v[0],
                             'x_permissions' : v[1]
                           }
        x = projcomp.projectuserperms( project=c.project )
        return h.todojoreadstore( x, fn, id='username', label='username' )

    @h.authorize( h.ValidUser( strict='True' ))
    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

    @h.authorize( h.ValidUser() )
    def index( self, environ ) :
        """List all the projects.
        URLS :
            /p
            /p?alphaindex=<alphaindex>
        """
        from zeta.config.environment    import projcomp, vfcomp

        c.rclose = h.ZResp()

        # Setup context for page generation
        x = projcomp.get_project( attrload=['admin', 'project_info'] )
        c.projects = x
        c.urlprojects = dict([ ( p.id, self.url_forproject( p.projectname )) for p in x ])
        c.title = 'ProjectIndex'

        byindex = {}
        [ byindex.setdefault( p.projectname[0], [] ).append(p) for p in x ]
        c.indexlist = sorted( byindex.keys() )
        if (c.alphaindex == None) and (len(c.projects) > h.MAX2SWITCH_ALPHAINDEX) :
            c.alphaindex = c.indexlist[0]
        if c.alphaindex :
            c.projects = byindex[c.alphaindex]

        # Html page generation
        c.rclose.append(render( '/derived/projects/index.html' ))
        return c.rclose

    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def projecthome( self, environ, projectname ) :
        """Project main-page for `projectname`
        URLS :
            /p/<projectname>
            /p/<projectname>?translate=1
            /p/<projectname>?jsonobj=projectlogo&view=js
            /p/<projectname>?jsonobj=projecticon&view=js
            /p/<projectname>?form=submit&formname=projfav&view=js
        """
        from zeta.config.environment    import projcomp, wikicomp, vfcomp

        c.rclose = h.ZResp()

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

        # Setup context for page generation
        c.projsummary = c.project.summary
        pt = {}
        [ pt.setdefault( t.teamtype.team_type, [] ).append( t.user.username )
          for t in c.project.team ]
        c.projectteams = pt
        c.att_editable = h.authorized( h.ProjectAdmin() )
        c.tag_editable = c.att_editable
        c.isfavorite = projcomp.checkfavorite( c.project.id, c.authuser.id )
        c.tags = self._prjtags( c.project )
        c.title = c.projectname

        fpurl = unicode( self.url_wikiurl( c.projectname, PROJHOMEPAGE ))
        w = wikicomp.get_wiki( fpurl, attrload=[ 'tablemap' ] )
        c.fpwcnt = wikicomp.get_content( w, translate=True ) if w else None
        c.fphtml = wikipage2html( c.fpwcnt, c.translate )

        # Html page generation
        if c.errmsg :
            html = self.returnerrmsg(environ)
        elif c.jsonobj and c.view == 'js' :
            html = self.handlejson(environ)
        elif c.view != 'js' :
            html = render( '/derived/projects/project.html' )
        c.rclose.append(html)
        return c.rclose


    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def roadmap( self, environ, projectname ) :
        """Milestones and report cards for project, `projectname`
        URLS :
            /p/<projectname>/roadmap
        """
        from zeta.config.environment    import projcomp, tckcomp

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.tck_typenames = tckcomp.tcktypenames
        c.tck_statusnames = tckcomp.tckstatusnames
        c.tck_severitynames = tckcomp.tckseveritynames
        c.title = projectname + ':roadmap'

        c.chart13_data = []
        c.mstnresolved = {}
        fn = lambda k, v : { 'name' : k, 'y' : v }
        for m in c.project.milestones :
            bystatus, bytypes, byseverity, byowner, c.mstnresolved[m.id] = \
                    h.chartify_mstn( c.mstntickets[m.id] )
            c.chart13_data.append(
                [ m.id,
                  map( fn, bytypes.iteritems() ),
                  map( fn, byseverity.iteritems() ),
                  map( fn, bystatus.iteritems() ),
                  map( fn, byowner.iteritems() ),
                ]
            )
        c.rclose.append(render( '/derived/projects/projroadmap.html' ))
        return c.rclose

    @h.authorize( h.HasPermname( ['PROJECT_VIEW' ] ))
    def milestone( self, environ, projectname, mstnid=None ) :
        """Individual milestone for project, `projectname`
        URLS :
            /p/<projectname>/m
            /p/<projectname>/m/<mstnid>
        """
        from zeta.config.environment    import projcomp, tckcomp

        h.redirect_url( h.url_projroadmap ) if not mstnid else None

        c.rclose = h.ZResp()

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.milestone = projcomp.get_milestone( int(mstnid) )
        m = c.milestone
        h.redirect_url( h.url_projroadmap
        ) if m and m.project_id != c.project.id else None

        c.tck_typenames = tckcomp.tcktypenames
        c.tck_statusnames = tckcomp.tckstatusnames
        c.tck_severitynames = tckcomp.tckseveritynames
        c.title = c.milestone.milestone_name

        c.chart13_data      = []
        bystatus, bytypes, byseverity, byowner, c.mstnresolved = \
                                h.chartify_mstn( c.mstntickets[m.id] )
        c.chart13_data = [
              m.id,
              map( fn, bytypes.iteritems() ),
              map( fn, byseverity.iteritems() ),
              map( fn, bystatus.iteritems() ),
              map( fn, byowner.iteritems() ),
        ]
        c.rclose.append(render( '/derived/projects/projmilestone.html' ))
        return c.rclose

    @h.authorize( h.ProjectAdmin() )
    def admin( self, environ, projectname ) :
        """Project administration page
        URLS :
            /p/<projectname>/admin?jsonobj=pcomplist&view=js
            /p/<projectname>/admin?jsonobj=mstnlist&view=js
            /p/<projectname>/admin?jsonobj=verlist&view=js
            /p/<projectname>/admin?jsonobj=projectteams&view=js
            /p/<projectname>/admin?jsonobj=teamperms&view=js
            /p/<projectname>/admin?jsonobj=prjattach&view=js
            /p/<projectname>/admin?jsonobj=prjtag&view=js
            /p/<projectname>/admin?jsonobj=prjtag&view=js
            /p/<projectname>/admin?form=request
            /p/<projectname>/admin?form=submit&formname=updateprj&view=js
            /p/<projectname>/admin?form=submit&formname=prjexp&view=js
            /p/<projectname>/admin?form=submit&formname=prjml&view=js
            /p/<projectname>/admin?form=submit&formname=prjirc&view=js
            /p/<projectname>/admin?form=submit&formname=addprjlogo&view=js
            /p/<projectname>/admin?form=submit&formname=delprjlogo&view=js
            /p/<projectname>/admin?form=submit&formname=addprjicon&view=js
            /p/<projectname>/admin?form=submit&formname=delprjicon&view=js
            /p/<projectname>/admin?form=submit&formname=createpcomp&view=js
            /p/<projectname>/admin?form=submit&formname=updatepcomp&view=js
            /p/<projectname>/admin?form=submit&formname=rmpcomp&view=js
            /p/<projectname>/admin?form=submit&formname=createmstn&view=js
            /p/<projectname>/admin?form=submit&formname=updatemstn&view=js
            /p/<projectname>/admin?form=submit&formname=mstnclose&view=js
            /p/<projectname>/admin?form=submit&formname=rmmstn&view=js
            /p/<projectname>/admin?form=submit&formname=createver&view=js
            /p/<projectname>/admin?form=submit&formname=updatever&view=js
            /p/<projectname>/admin?form=submit&formname=rmver&view=js
            /p/<projectname>/admin?form=submit&formname=addprjteam&view=js
            /p/<projectname>/admin?form=submit&formname=delprjteam&view=js
            /p/<projectname>/admin?form=submit&formname=addteamperms&view=js
            /p/<projectname>/admin?form=submit&formname=delteamperms&view=js
            /p/<projectname>/admin?form=submit&formname=addprjattachs&view=js
            /p/<projectname>/admin?form=submit&formname=delprjattachs&view=js
            /p/<projectname>/admin?form=submit&formname=addprjtags&view=js
            /p/<projectname>/admin?form=submit&formname=delprjtags&view=js
        """
        from zeta.config.environment import userscomp, liccomp, projcomp, vfcomp
    
        formnames = [ 'updateprj', 'prjexp', 'prjml', 'prjirc', 'addprjlogo',
                      'delprjlogo', 'addprjicon', 'delprjicon', 'createpcomp',
                      'updatepcomp', 'rmpcomp', 'createmstn', 'updatemstn',
                      'mstnclose', 'rmmstn', 'createver', 'updatever', 'rmver',
                      'addprjteam', 'delprjteam', 'addteamperms',
                      'delteamperms', 'addprjattachs', 'delprjattachs',
                      'addprjtags', 'delprjtags', ]

        c.rclose = h.ZResp()

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

        # Setup context for page generation
        c.projsummary = c.project.summary
        c.logo_editable= c.icon_editable= c.tag_editable = True
        c.pcomplist = c.mstnlist = c.verlist = []
        c.title = projectname+':admin'
        if c.view != 'js' :
            c.licensenames = sorted(liccomp.licensenames)
            c.projusers    = sorted(
                                projcomp.projusernames( c.project ) + \
                                [ c.project.admin.username ]
                             )
            c.usernames = userscomp.usernames
            c.teamtypes_p  = projcomp.teams
            c.teamtypes = c.teamtypes_p[:]
            c.teamtypes.remove( projcomp.team_nomember )
            c.logoattach = self._projlogo( c.project )
            c.iconattach = self._projicon( c.project )

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

        elif c.view == 'js' and \
           c.formname in [ 'addprjlogo', 'addprjicon', 'addprjattachs' ] :
            html = IFRAME_RET

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

        elif c.view == 'js' :
            html = ''

        else :
            # Context specific to project admin form
            c.projectteams = projcomp.projectteams(
                                project=c.project, teamnames=c.teamtypes_p,
                                usernames=c.usernames,
                             )
            c.isfavorite = projcomp.checkfavorite( c.project.id, c.authuser.id )

            deftt = sorted(c.projectteams.keys())[0]
            c.defteamtype= deftt
            c.teamusers = map( lambda pr : pr[1], c.projectteams[deftt][0] )
            c.x_teamusers = c.projectteams[deftt][1]

            c.teamperms = projcomp.teamperms(
                                project=c.project, teamnames=c.teamtypes_p,
                          )
            c.teampgroups = map( lambda pr : pr[1], c.teamperms[deftt][0] )
            c.x_teampgroups= c.teamperms[deftt][1]

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

    @h.authorize( h.HasPermname([ 'PROJECT_VIEW' ]))
    def timeline( self, environ, projectname ) :
        """Aggregate all the activities under the project
        URLS :
            /p/<projectname>/timeline
        """
        from zeta.config.environment    import projcomp, tlcomp

        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.project = c.project or projcomp.get_project( projectname )
        c.projectname = c.project.projectname
        c.projsummary = c.project.summary
        c.title = projectname + ':timeline'
        c.alllogs = tlcomp.fetchprojlogs(
                        c.project, limit=h.TLCOUNT+2, id=logid, direction=dir
                    )
        routeargs = { 'projectname' : projectname }
        self.tline_controller(
            h.r_projtline, routeargs, [], fromoff, logid, dir, c.project
        )
        h.url_rssfeed = h.url_for( h.r_projfeed, projectname=projectname )
        c.datatline, c.startdt = h.tlineplot( c.logs[:] )

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

    @h.authorize( h.ProjectAdmin() )
    def timelineadmin( self, environ, projectname ) :
        """Aggregate all the activities under the project
        URLS :
            /p/<projectname>/timeline/admin"""
        from zeta.config.environment    import projcomp

        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
        routeargs  = { 'projectname' : projectname }
        self.tline_controller(
                h.r_projadmtline, routeargs, 'project',
                fromoff, logid, dir, c.project
        )
        c.title = projectname + ':admintimeline'
        h.url_rssfeed = h.url_for( h.r_projadmfeed, projectname=projectname )
        c.datatline, c.startdt = h.tlineplot( c.logs[:] )

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

    @h.authorize( h.HasPermname([ 'PROJECT_VIEW' ]))
    def downloads( self, environ, projectname ) :
        """Action to present project downloads
        URLS : 
            /p/<projectname>/downloads
        """
        from zeta.config.environment    import projcomp

        c.rclose = h.ZResp()

        # Setup context for html page
        c.projsummary = c.project.summary
        c.title = 'ProjectDownloads'
        attachments = projcomp.attachments( c.project )
        c.attachments = {}
        for pkey, adict in attachments.iteritems() :
            attachs = []
            for aid, a in adict.iteritems() :
                if 'download' not in a[-1] : continue
                a[-1].remove( 'download' )
                attachs.append( 
                    [ aid ] + adict[aid][:-1] + [ ', '.join(a[-1]) ] + \
                    [ self.url_attachdownl( aid ) ]
                )
            c.attachments[ pkey[1] ] = attachs

        # Html page generation
        c.rclose.append(render( '/derived/projects/projdownloads.html' ))
        return c.rclose


    @h.authorize( h.HasPermname([ 'PROJECT_VIEW' ]))
    def attachs( self, environ, projectname ) :
        """Action to present attachment page for `projectname`
        URLS :
            /p/<projectname>/attachs
        """
        from zeta.config.environment    import projcomp, vfcomp

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.editable = c.att_editable = h.authorized( h.ProjectAdmin() )
        c.title    = 'ProjectAttachs'
        c.projsummary = c.project.summary
        attachments  = projcomp.attachments( c.project )
        c.attachments = self.attachments( attachments )
        c.attachs = self._prjattachs( c.project )
        c.isfavorite = projcomp.checkfavorite( c.project.id, c.authuser.id )

        # Html page generation
        c.rclose.append(render( '/derived/projects/projattachs.html' ))
        return c.rclose

    @h.authorize( h.HasPermname([ 'PROJECT_VIEW' ]))
    def charts( self, environ, projectname ) :
        """Chart analytics for project `projectname`
        URLS :
            /p/<projectname>/charts
            /p/<projectname>/charts?chartname=<name>
        """

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.projectname = c.project.projectname
        c.projsummary = c.project.summary
        c.chartname = c.chartname or 'chart14'
        c.selectedchart = (c.chartname, self._charts[c.chartname])
        c.chartoptions = [ ( self.url_projchart( projectname, name), text
                           ) for name, text in self._charts.iteritems() ]
        c.pa = ca.get_analyticobj( 'projects' )
        c.title = '%s:Charts' % projectname

        # Html page generation
        if c.chartname == 'chart14' :
            c.chart14_data = getattr( c.pa, 'chart14_data', {}
                                    ).get( projectname, {} ).items()
        elif c.chartname == 'chart15' :
            dates    = []
            mstns    = []
            for m in c.project.milestones :
                created_on = timezone('UTC').localize(m.created_on)
                dates.extend([ created_on, m.due_date ])
                mstns.append(( m, created_on, m.due_date ))
            mstns    = sorted( mstns, key=lambda x: x[1] )
            dates    = sorted(filter( None, dates ))

            c.chart15_data = []
            for mstn in mstns :
                m      = mstn[0]
                mrange = mstn[1:3]
                # stacked bar : open, cancelled, completed
                if not mrange[1] :
                    days = (dates[-1]-mrange[0]).days
                elif mrange[1] > mrange[0] :
                    days = (mrange[1]-mrange[0]).days
                elif mrange[1] <= mrange[0] :
                    days = 0

                bar = [ (mrange[0]-dates[0]).days ]
                if m.completed :
                    bar.extend( [0, 0, days] )
                elif m.cancelled :
                    bar.extend( [0, days, 0] )
                else :
                    bar.extend( [days, 0, 0] )
                c.chart15_data.append( [m.milestone_name] + bar )

            date            = dates and dates[0] or None
            c.chart15_frmdt = h.date2jsdate( date, [ '2000', '0', '1' ] )

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

    def feedadmin( self, environ, projectname ) :
        """Aggregate all the activities under the project
        URLS :
            /p/<projectname>/feed/admin
        """
        from zeta.config.environment    import projcomp

        # Setup context for page generation
        c.projsummary = c.project.summary
        title = projectname + ':admintimeline'
        link = h.urlroot(environ)
        descr = 'Timeline for project administration, %s' % projectname
        feed = h.FeedGen( title, link, descr )
        routeargs  = { 'projectname' : projectname }
        self.tline_controller(
            h.r_projadmtline, routeargs, '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 ) :
        """Aggregate all the activities under the project, and provide them as
        feed
        URLS :
            /p/<projectname>/feed
        """
        from zeta.config.environment    import tlcomp

        # Setup context for page generation
        c.projsummary = c.project.summary
        title = projectname + ':timeline'
        link = h.urlroot(environ)
        descr = 'Timeline for project, %s' % projectname
        c.alllogs = tlcomp.fetchprojlogs( c.project, limit=h.TLCOUNT+1, id=None)
        c.logs = c.alllogs[:100]
        feed = h.FeedGen( title, link, descr )
        feedhtml = self.feeds( environ, link, feed, c.logs )
        response.content_type = 'application/atom+xml'
        return feedhtml

    def __after__( self ) :
        """Called calling any actions under this controller"""
        self.aftercontrollers()
Beispiel #6
0
class UserpageController( BaseController ) :
    """Actions to handle user pages"""

    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 )

        # Collect the query values into 'context'
        c.stdfilter = request.params.get( 'stdfilter', None )
        c.alphaindex = request.params.get( 'alphaindex', None )
        c.savfilter = request.params.get( 'savfilter', None )
        c.savfilter = c.savfilter and int(c.savfilter)

    def _userphoto( self, u ) :
        return self.modelattachments( u, 'photofile') if u.photofile else {}

    def _usericon( self, u ) :
        return self.modelattachments( u, 'iconfile') if u.iconfile else {}

    def _json_usernames( self, users=[] ) :                 # JSON
        """JSON: { id   : '',
                   label: '',
                   items: [ { usernames: usernames } ]
                 }"""
        from zeta.config.environment import userscomp

        usernames = [ u.username for u in users
                    ] if users else sorted( userscomp.usernames )
        return h.todojoreadstore( [ usernames ], lambda v : { 'usernames': v } )

    @h.authorize( h.ValidUser( strict='True' ))
    def _json_userphoto( self ) :                           # JSON
        """JSON: { id : [ id, url, filename, summary } """
        return json.dumps( self._userphoto( c.authuser ) )


    @h.authorize( h.ValidUser( strict='True' ))
    def _json_usericon( self ) :
        """JSON: { id : [ id, url, filename, summary } """
        return json.dumps( self._usericon( c.authuser ) )


    @h.authorize( h.ValidUser( strict='True' ))
    def _json_userperms( self ) :                           # JSON
        """JSON: { id   : 'username',
                   label: 'username',
                   items: [ { username: username,
                              permissions: permissions,
                              x_permissions: ^permissions },
                            ... ]
                 }"""
        from zeta.config.environment import userscomp

        fn = lambda k, v : { 'username'      : k,   'permissions'   : v[0],
                             'x_permissions' : v[1] },
        x = userscomp.userpermission_map()
        return h.todojoreadstore( x, fn, id='username', label='username' )

    @h.authorize( h.SiteAdmin() )
    def _json_userstatus( self ) :                          # JSON
        """JSON: { id   : 'status',
                   label: 'status',
                   items: [ { status: status, usernames: usernames },
                            ... ]
                 }"""
        from zeta.config.environment import userscomp
        fn = lambda k, v : { 'status' : k, 'usernames' : v }
        x = userscomp.userstatus
        return h.todojoreadstore( x, fn, id='status', label='status' )

    @h.authorize( h.ValidUser( strict='True' ))
    def _json_userconns( self ) :                           # JSON
        """JSON: { id   : '',
                   label: '',
                   items: [ touserrels, fromuserrels, potrels ]
                 }
             touserrels  : { type : [ (tousr, rel.id, approved), ... ], ... }
             fromuserrels: { type : [ (fromsr, rel.id, approved), ... ], ... }
             potrels     : { type : [ [ username, ...], ... }"""
        from zeta.config.environment import userscomp

        json = []
        touserrels, fromuserrels, potrels = userscomp.get_connections( c.authuser
               ) if c.authusername != 'anonymous' else ( [], [], [] )
        fn = lambda rt, val : ( rt, sorted( val, key=lambda x : x[0] ) )

        touserrels = dict( map( fn, touserrels.iteritems() ))
        fromuserrels = dict( map( fn, fromuserrels.iteritems() ))
        potrels = dict([ ( rt, sorted( potrels[rt] ) ) for rt in potrels ])

        return h.todojoreadstore( [ [ touserrels, fromuserrels, potrels ] ],
                                  lambda v : { 'rels' : v } )


    @h.authorize( h.ValidUser( strict='True' ))
    def _json_ticketlist( self ) :                          # JSON-GRID
        """Fetch the json object with caching, under `username`
       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( tup[1], 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      = sorted( tckcomp.ticketlist(
                                            user=c.authuser, filters=filters
                               ).values(),
                               key=lambda l : l[0], reverse=True
                             )
        _tl =  h.todojoreadstore( tcklist,
                                  format_item,
                                  id='id',
                                  label='ticket_id'
                                )
        return _tl


    @h.authorize( h.ValidUser( strict='True' ))
    def index( self, environ ) :
        """Index of all registered users
        URLS :
            /u
            /u?alphaindex=<a>
        """
        from zeta.config.environment import userscomp

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.users = userscomp.get_user( attrload=[ 'userinfo', 'photofile' ] )
        byindex = {}
        [ byindex.setdefault( u.username[0], [] ).append(u) for u in c.users ]
        c.indexlist = sorted( byindex.keys() )
        if (c.alphaindex == None) and (len(c.users) > h.MAX2SWITCH_ALPHAINDEX) :
            c.alphaindex = c.indexlist[0]
        if c.alphaindex :
            c.users = byindex[c.alphaindex]
        c.urlusersphoto = dict([
            ( u.id, h.url_attach( u.photofile.id ) )
            for u in c.users if u.photofile
        ])
        c.title = 'Users'

        # Html page generation
        if c.jsonobj and c.view == 'js' :
            html = self.handlejson(environ)
        else :
            html = render( '/derived/userpage/usersindex.html' )
        c.rclose.append(html)
        return c.rclose


    @h.authorize( h.ValidUser( strict='True' ))
    def gmap( self, environ ) :
        """all registered users on google map
        URLS :
            /u/gmap
        """
        from zeta.config.environment import userscomp

        c.rclose = h.ZResp()
        # Setup context for page rendering
        c.useraddrs = [ [ u.username, h.useraddress( u.userinfo ) ]
                        for u in userscomp.get_user(attrload=['userinfo'])
                      ]
        c.googlemaps= h.gmapkey( c.sysentries )
        c.title = 'UsersOnGooglemap'

        # Html page generation
        c.rclose.append(render( '/derived/userpage/usersgmap.html' ))
        return c.rclose

    @h.authorize( h.ValidUser( strict='True' ))
    def inviteuser( self, environ ) :
        """Invite a new user to join the site
        URLS : 
            /u/inviteuser
            /u/inviteuser?form=submit&formname=inviteuser
        """
        from zeta.config.environment    import vfcomp

        c.rclose = h.ZResp()

        # Authorize: This context attribute should be set before calling the
        # viewcontext() method.
        regrbyinvite = h.str2bool( c.sysentries['regrbyinvite'] )
        invitebyall  = h.str2bool( c.sysentries['invitebyall'] )

        c.usercaninvite = \
               ( regrbyinvite and invitebyall and \
                        h.authorized( h.ValidUser( strict='True' ))  \
               ) or \
               ( regrbyinvite and h.authorized( h.SiteAdmin() ) )

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

        c.title = 'InviteUser'

        # Html page generation
        if c.usercaninvite :
            html = render( '/derived/userpage/inviteuser.html' )
        else :
            html = render( '/derived/userpage/inviteuser.html' )
        c.rclose.append(html)
        return c.rclose

    @h.authorize( h.ValidUser( strict='True' ))
    def userhome( self, environ, username ) :
        """User Home page
        URLS :
            /u/{username}
            /u/{username}?jsonobj=userphoto&view=js
            /u/{username}?jsonobj=usericon&view=js
        """
        from zeta.config.environment import \
                userscomp, attcomp, projcomp, tckcomp, wikicomp, revcomp, \
                votecomp, tlcomp

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.username = username
        c.user  = userscomp.get_user( username, 
                                      attrload=[ 'userinfo' ],
                                      attrload_all=[ 'owncomponents.project' ]
                                    )
        votes   = votecomp.uservotes( c.user )
        c.statistics = {
            'uploadedfiles' : len(attcomp.uploadedbyuser( c.user )),
            'votes'         : dict([ ( votedas, len(votes[votedas]) )
                                     for votedas in votes ]),
            'adminprojects' : projcomp.adminprojects( c.user ),
            'inprojects'    : projcomp.userprojects( c.user ),
            'tickets'       : len(tckcomp.usertickets( c.user ).keys()),
            'tckcomments'   : len(tckcomp.usercomments( c.user )),
            'wikicomments'  : len(wikicomp.usercomments( c.user )),
            'authoredrevw'  : len(revcomp.userasauthor( c.user )),
            'modertrevw'    : len(revcomp.userasmoderator( c.user )),
            'particprevw'   : len(revcomp.userasparticipant( c.user )),
            'revwcomments'  : len(revcomp.usercomments( c.user )),
        }
        c.googlemaps = h.gmapkey( c.sysentries )
        c.logs = tlcomp.fetchlogs( 'user', c.user, limit=20 )
        c.useraddr= [ [ username, h.useraddress( c.user.userinfo ) ] ]
        photofile = c.user.photofile
        h.url_userphoto = photofile and self.url_attach(photofile.id)
        c.projecturls = self.projecturls( projcomp.projectnames )
        c.title = username

        # Html page generation
        if c.jsonobj and c.view == 'js' :
            html = self.handlejson(environ)
        else :
            html = render( '/derived/userpage/userhome.html' )
        c.rclose.append(html)
        return c.rclose

    @h.authorize( h.ValidUser( strict='True' ))
    def preference( self, environ, username, **kwargs ) :
        """Handle user preference
        URLS :
            /u/{username}/preference?form=request
            /u/{username}/preference?form=submit&formname=updateuser&view=js
            /u/{username}/preference?form=submit&formname=updtpass&view=js
            /u/{username}/preference?form=submit&formname=userphoto&view=js
            /u/{username}/preference?form=submit&formname=deluserphoto&view=js
            /u/{username}/preference?form=submit&formname=usericon&view=js
            /u/{username}/preference?form=submit&formname=delusericon&view=js
            /u/{username}/preference?form=submit&formname=adduserrels&view=js
            /u/{username}/preference?form=submit&formname=approveuserrels&view=js
            /u/{username}/preference?form=submit&formname=deluserrels&view=js
        """
        from zeta.config.environment    import vfcomp

        c.rclose = h.ZResp()

        # Form handling
        def errhandler(errmsg) :
            c.errmsg = errmsg
        if c.usercaninvite :
            vfcomp.process(
                request, c, defer=True, errhandler=h.hitchfn(errhandler),
                formnames=[ 'updateuser', 'updtpass', 'userphoto',
                'deluserphoto', 'usericon', 'delusericon', 'adduserrels',
                'approveuserrels', 'deluserrels' ], user=c.authuser
            )

        # Setup context for page rendering
        uinfo            = c.authuser.userinfo
        c.title          = 'Preference'
        c.photo_editable = c.icon_editable = h.authorized( h.ValidUser( strict='True' ))
        c.photoattach    = self._userphoto( c.authuser )
        c.iconattach     = self._usericon( c.authuser )
        c.googlemaps     = h.gmapkey( c.sysentries )
        c.fulladdress    = h.useraddress( uinfo )

        # Html page generation
        if c.view == 'js' and c.formname in [ 'userphoto', 'usericon' ] :
            html = IFRAME_RET
        else :
            html = render( '/derived/userpage/preference.html' )
        c.rclose.append(html)
        return c.rclose

    @h.authorize( h.ValidUser( strict='True' ))
    def tickets( self, environ, username ) :
        """List tickets belonging to user (attributed as owner and/or
        promptuser
        URLS :
            /u/{username}/t
            /u/{username}/t?stdfilter=<name>
            /u/{username}/t?savfilter=<name>
            /u/{username}/t?form=submit&formname=addtckfilter&view=js
            /u/{username}/t?form=submit&formname=deltckfilter&view=js
        """
        from zeta.config.environment    import projcomp, tckcomp, vfcomp

        c.rclose = h.ZResp()

        # Setting up urls to be stuffed into the page
        kwargs = { 'username' : username }
        c.stdfilter and kwargs.update({ 'stdfilter' : c.stdfilter })
        c.savfilter and kwargs.update({ 'savfilter' : c.savfilter })
        h.url_ticketlist = self.url_usrtcks( **kwargs )

        # Handle forms
        def errhandler(errmsg) :
            c.errmsg = errmsg
        if c.form in [ 'request', 'submit' ] and \
           c.formname in [ 'addtckfilter', 'deltckfilter' ] and \
           h.authorized( h.UserIn([ username ]) ) :
            vfcomp.process(
                request, c, defer=True, errhandler=h.hitchfn(errhandler),
                formnames=[ 'addtckfilter', 'deltckfilter' ], user=c.authuser
            )

        # Setup context for both html page and AJAX request.
        c.tckfilters = h.compile_tckfilters( tckfilters )
        c.title = '%s:tickets' % c.authuser.username

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

        elif c.view != 'js' and not (c.stdfilter or c.savfilter) and c.tckfilters :
            kw = { 'username' : username, 'stdfilter' : c.tckfilters[0][0] }
            h.redirect_url( self.url_usrtcks( **kw ))

        elif c.view != 'js' :
            # Setup context for html page
            c.tckeditable = False
            c.tckccodes = h.tckccodes
            c.tstat_resolv = h.parse_csv( c.sysentries.get( u'ticketresolv', '' ))

            c.tck_typenames = tckcomp.tcktypenames
            c.tck_statusnames = tckcomp.tckstatusnames
            c.tck_severitynames = tckcomp.tckseveritynames
            c.projectnames = projcomp.projectnames

            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_usrtcks(**{'username' : username, 'savfilter' : k })
                                 v[0] ]
            c.savfilterlist = map( fn, c.savfilterlist.iteritems() )
            html = render( '/derived/userpage/ticket.html' )

        else :
            html =''

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

    _userscharts = {
        'chart8'  : 'user activity',
        'chart9'  : 'user-site-permissions',
        'chart10' : 'project-administrators',
        'chart11' : 'component-owners',
    }

    @h.authorize( h.ValidUser( strict='True' ))
    def charts( self, environ ) :
        """Charts for combined users
        URLS :
            /u/charts
            /u/charts?chartname=<name>
        """
        from zeta.config.environment import userscomp

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.chartname = c.chartname or 'chart8'
        c.selectedchart = (c.chartname, self._userscharts[c.chartname])
        c.chartoptions = [ (self.url_userschart(name), text)
                           for name, text in self._userscharts.iteritems() ]

        c.ua     = ca.get_analyticobj( 'users' )

        if c.chartname == 'chart8' :    # User activity
            c.chart8_data  = getattr( c.ua, 'chart8_data', [] )
        elif c.chartname == 'chart9' :  # User site-permission
            c.chart9_data  = getattr( c.ua, 'chart9_data', [] )
        elif c.chartname == 'chart10' : # project administrators
            c.chart10_data = getattr( c.ua, 'chart10_data', [] )
        elif c.chartname == 'chart11' : # Component owners
            c.chart11_data = getattr( c.ua, 'chart11_data', [] )
            c.chart11_ccnt = getattr( c.ua, 'chart11_ccnt', [] )

        c.title = 'Users:Charts'

        # Html page generation
        c.rclose.append(render( '/derived/userpage/userscharts.html' ))
        return c.rclose

    _usercharts = {
        'chart12'  : 'project activities',
    }

    @h.authorize( h.ValidUser( strict='True' ))
    def usercharts( self, environ, username='' ) :
        """User charts
        URLS :
            /u/{username}/charts
            /u/{username}/charts?chartname=<name>
        """
        from zeta.config.environment import userscomp

        c.rclose = h.ZResp()

        # Setup context for page rendering
        c.chartname = c.chartname or 'chart12'
        c.selectedchart = (c.chartname, self._usercharts[c.chartname])
        c.chartoptions = [ (self.url_userschart(name), text)
                           for name, text in self._usercharts.iteritems() ]

        c.user = userscomp.get_user( unicode(username) )
        c.ua   = ca.get_analyticobj( 'users' )

        data   = getattr( c.ua, 'chart12_data', {} ).get(
                          c.user.id, [ c.user.id, c.user.username, [] ] )
        c.chart12_data = data
        c.title   = '%s:Charts' % username

        # Html page generation
        c.rclose.append(render( '/derived/userpage/usercharts.html' ))
        return c.rclose

    @h.authorize( h.ValidUser( strict='True' ))
    def timelines( self, environ ) :
        """User timelines
        URLS :
            /u/timeline
        """
        from zeta.config.environment import userscomp

        c.rclose = h.ZResp()

        # Action specific query parameters
        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)
        
        c.user = None
        self.tline_controller(
            h.r_userstline, {}, 'user', fromoff, logid, dir, c.user
        )
        c.title = 'Users:timeline'
        c.datatline, c.startdt = h.tlineplot( c.logs[:] )
        c.timeline = True

        # Html page generation
        c.rclose.append(render( '/derived/userpage/usertline.html' ))
        return c.rclose

    @h.authorize( h.ValidUser( strict='True' ))
    def timeline( self, environ, username ) :
        """User timeline
        URLS :
            /u/timeline/{username}
        """
        from zeta.config.environment import userscomp

        c.rclose = h.ZResp()

        # Action specific query parameters
        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)
        
        c.user = userscomp.get_user( username )
        self.tline_controller(
            h.r_usertline, { 'username' : username }, [ 'user' ],
            fromoff, logid, dir, c.user
        )
        c.title   = '%s:timeline' % username
        c.datatline, c.startdt = h.tlineplot( c.logs[:] )
        c.timeline = True

        # Html page generation
        c.rclose.append(render( '/derived/userpage/usertline.html' ))
        return c.rclose

    def feeds( self, environ ) :
        """Feed for user timeline
        URLS :
            /u/feed
        """
        from zeta.config.environment import userscomp

        title = 'UsersTimeline'
        link = h.urlroot(environ)
        descr = 'Timeline for all users'
        c.user = None
        feed   = h.FeedGen( title, link, descr )
        self.tline_controller( h.r_userstline, {}, 'user', 1, None, None, c.user )
        feedhtml = self.feeds( environ, link, feed, c.logs )
        response.content_type = 'application/atom+xml'
        return feedhtml

    def feed( self, environ, username ) :
        """Feed for user timeline
        URLS :
            /u/feed/{username}
        """
        from zeta.config.environment import userscomp

        title = '%s:timeline' % c.user.username
        link = h.urlroot(environ)
        descr = 'Timeline for user %s' % c.user.username
        c.user = userscomp.get_user( username )
        feed   = h.FeedGen( title, link, descr )
        self.tline_controller( 
            h.r_usertline, { 'username': username },
            'user', 1, None, None, c.user
        )
        feedhtml = self.feeds( environ, link, feed, c.logs )
        response.content_type = 'application/atom+xml'
        return feedhtml

    def __after__( self ) :
        """Called calling any actions under this controller"""
        self.aftercontrollers() # Genering, app-level after-controller handler
Beispiel #7
0
class AttachmentController( BaseController ) :
    """Actions to handle user pages"""

    _charts = {
        'chart2': 'By Uploaders',
        'chart3': 'By download-count',
        'chart4': 'By tag',
        'chart5': 'By timestamp',
    }

    def __before__( self, environ=None ) :
        """Called before calling any actions under this controller"""

        # Collect the query values into 'context'
        c.fromid = request.params.get( 'fromid', None )
        c.all = request.params.get( 'all', None )

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

    @h.authorize( h.ValidUser() )
    def index( self, environ ) :
        """List of all attachments
        URLS :
            /attachment
            /attachment?fromid=<number>
            /attachment?all=1
            /attachment?form=submit&formname=attachssummary&view=js
            /attachment?form=submit&formname=attachstags&view=js
        """
        from zeta.config.environment    import attcomp, vfcomp

        c.rclose = h.ZResp()
        h.url_attachpages = self.url_attachpages()

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

        try :
            fromid = c.fromid and int(c.fromid)
            fromid -= 1
        except :
            fromid = None
        c.title = 'Attachments'
        c.aa = ca.get_analyticobj( 'attachs' )
        c.ua = ca.get_analyticobj( 'users' )
        c.la = ca.get_analyticobj( 'license' )
        c.pa = ca.get_analyticobj( 'projects' )
        c.ta = ca.get_analyticobj( 'tickets' )
        c.ra = ca.get_analyticobj( 'reviews' )
        c.wa = ca.get_analyticobj( 'wiki' )

        # Html page generation
        if c.errmsg :
            html = self.returnerrmsg(environ)
        elif c.view == 'js' :
            html = ''
        else :
            limit = 100 if c.all == None else None
            attachments = attcomp.attachments( offset=fromid, limit=limit )
            attachs = [ [ aid ] + attachments[aid][:-1] + \
                        [ ', '.join(attachments[aid][-1]) ] + \
                        [ self.url_attachdownl( aid ) ]
                        for aid in attachments ]
            c.attachassc= attcomp.attachassc()
            c.attachments = { 'all-attachments' : attachs }
            c.editable = h.authorized( h.ValidUser( strict='True' ))

            html = render( '/derived/attachs/index.html' )

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

    @h.authorize( h.ValidUser( strict='True' ) )
    def add( self, environ ) :
        """Add a new attachment
        URLS :
            /attachment/add?form=request&formname=addattachs
            /attachment/add?form=submit&formname=addattachs
        """
        from zeta.config.environment    import vfcomp

        c.rclose = h.ZResp()

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

        # Setup context for page generation
        c.title = 'AddAttachs'

        # Html page generation
        if c.errmsg :
            html = self.returnerrmsg(environ)
        else :
            html = render( '/derived/attachs/add.html' )

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

    @h.authorize( h.ValidUser() )
    def attach( self, environ, id ) :
        """Provide the attachment's content
        URLS :
            /attachment/{id}
        """
        from zeta.config.environment    import attcomp

        attach = attcomp.get_attach( int(id) )
        if attach :
            return str(attcomp.content(attach))
        else : 
            response.status_int = 400
            return 'No attachment by id %s' % id

    @h.authorize( h.ValidUser() )
    def download( self, environ, id ) :
        """Prompt browser to download the attachment.
        URLS :
            /attachment/download/{id}
        """
        from zeta.config.environment    import attcomp

        attach, content = attcomp.downloadattach( int(id) )

        if attach :
            response.headers['Content-disposition'] = \
                str( 'attachment; filename="%s"' % attach.filename )

        else :
            response.status_int = 400
            return 'No attachment by id %s' % id

        return str(content)

    @h.authorize( h.ValidUser() )
    def charts( self, environ ) :
        """Attachment charts
        URLS :
            /attachment/charts
            /attachment/charts?chartname=<name>
        """
        # Setup context for page generation
        c.rclose = h.ZResp()
        c.chartname = c.chartname or 'chart2'
        c.selectedchart = ( c.chartname, self._charts[c.chartname] )
        c.chartoptions = [
            ( h.url_attachcharts( name ), text )
            for name, text in self._charts.iteritems()
        ]
        c.ta = ca.get_analyticobj( 'tags' )
        c.aa = ca.get_analyticobj( 'attachs' )

        if c.chartname == 'chart2' :    # user Vs attachments
            c.chart2_data = getattr( c.aa, 'chart2_data', [] )
            c.chart2_fcnt = getattr( c.aa, 'chart2_fcnt', 0 )
            c.chart2_payld= getattr( c.aa, 'chart2_payld', 0 )

        elif c.chartname == 'chart3' :  # attachment Vs download
            c.chart3_data = getattr( c.aa, 'chart3_data', [] )

        elif c.chartname == 'chart4' :  # attachment Vs tags
            c.chart4_data = getattr( c.ta, 'chart4_data', [] )
            c.chart4_tags = getattr( c.ta, 'chart4_tags', [] )

        elif c.chartname == 'chart5' :  # attachment Vs uploaded time
            c.chart5_data = getattr( c.aa, 'chart5_data', [] )
            date = c.chart5_data and c.chart5_data[0][0][3] or None
            c.chart5_frmdt= h.date2jsdate( date, [ '2000', '0', '1' ] )
            c.chart5_data = [ [ l[:3] for l in logs ] for logs in c.chart5_data ]

        c.title = "Attachment:Charts"

        # Html page generation
        c.rclose.append(render( '/derived/attachs/charts.html' ))
        return c.rclose

    @h.authorize( h.ValidUser() )
    def timeline( self, environ ) :
        """Timeline on attachments.
        URLS :
            /attachment/timeline
        """
        c.rclose = h.ZResp()

        # Action specific query parameters
        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.links = [ '', '', '' ]
        self.tline_controller(
            h.r_attachtimeline, {}, 'attachment',
            fromoff, logid, dir, modelobj=None
        )
        c.title = 'AttachTimeline'
        c.timeline = True

        # Html page generation
        c.rclose.append(render( '/derived/attachs/tline.html' ))
        return c.rclose

    
    def feed( self, environ ) :
        """feed on attachments.
        URLS :
            /attachment/feeds
        """
        self.tline_controller(
            h.r_attachtimeline, {}, 'attachment',
            1, None, None, modelobj=None
        )
        title = 'AttachTimeline'
        link = h.urlroot(environ)
        descr = 'Timeline for Attachments'

        feed   = h.FeedGen( title, link, descr )
        for l in c.logs :
            summary, lnk, content = h.log2feed( l )
            feed.add_item(
                    summary, '%s%s' % (link,lnk), content,
                    pubdate=l.created_on, unique_id=str(l.id),
                    author_name=l.user.username
            )
        response.content_type = 'application/atom+xml'
        feedhtml = feed.writeString('utf-8')
        return feedhtml

    def __after__( self ) :
        """Called calling any actions under this controller"""
        self.aftercontrollers() # Genering, app-level after-controller handler
Beispiel #8
0
class HomeController(BaseController):
    """All the pages returned by this controller are static wiki pages"""
    def __before__(self, environ):
        """Called before calling any actions under this controller"""

        # Collect the query values into 'context'
        c.editsw = request.params.get('editsw', None)
        c.delsw = request.params.get('delsw', None)
        c.refresh = request.params.get('refresh', None)
        c.previewtype = request.params.get('previewtype', None)

        # Common logic for this controller
        c.searchfaces = [('staticwiki', '1')]

        # Initialize context
        c.swurl = None
        c.swiki = None
        c.swhtml = ''

        # Generic, app-level before-controller handler
        self.beforecontrollers(environ=environ)
        c.swurl = c.routes_d.get('swurl', '')
        if c.controlleraction == 'index':
            c.swurl = u'frontpage'
        self.dourls(environ, None)
        c.metanavs = metanav(environ)

    def formpermission(self):
        return c.form in [ 'submit', 'request' ] and \
               not h.authorized( h.HasPermname( 'STATICWIKI_CREATE' ))

    def listswdir(self):
        swentry = lambda x: x[1] and (x[0], x[2], self.url_editsw(x[2]),
                                      self.suburl_delsw(x[2]))
        l = [[sw.id] + h.checksuburl(sw.path, c.swurl)
             for sw in syscomp.get_staticwiki()]
        c.swikis = filter(None, map(swentry, l))

    @h.authorize(h.HasPermname('STATICWIKI_CREATE'))
    def _text_swpreview(self):  # TEXT
        """Translate wiki markup text into HTML and send back to browser"""
        o = h.Preview()
        text = request.POST.get('text', '')
        setattr(o, 'text', text)
        o.translate = h.hitch(o, h.Preview, h.translate, cacheattr='text')
        html = o.translate(wtype=c.previewtype, wiki=c.swiki)
        return html

    def _publicfile(self, url):
        """Check for public file, which are not present and so gets redirected
        here"""
        return True if url in PUBLICFILES else False

    @h.authorize(h.ValidUser())
    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

    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

    @h.authorize(h.ValidUser())
    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

    @h.authorize(h.ValidUser())
    def staticwiki(self, environ, swurl):
        """Static Wiki - every thing else
        URLS :
            /tos
            /aboutus
            /help/
            /(swurl)
            /(swurl)?refresh=1
            /(swurl)?textobj=swpreview&view=text
            /(swurl)?editsw=1&form=request&formname=editsw
            /(swurl)?form=submit&formname=editsw&view=js
            /(swurl)?form=submit&formname=delsw&delsw=1
        """
        from zeta.config.environment import vfcomp, syscomp, wikicomp

        c.rclose = h.ZResp()
        c.sweditable = h.authorized(h.HasPermname('STATICWIKI_CREATE'))

        # Form handling
        if self.formpermission():
            c.errmsg = 'Do not have STATICWIKI_CREATE permission !!'

        def errhandler(errmsg):
            c.errmsg = errmsg

        kwargs = {'pathurl': swurl} if c.formname == 'delsw' else {}
        kwargs['user'] = c.authuser
        vfcomp.process(request,
                       c,
                       defer=True,
                       errhandler=h.hitchfn(errhandler),
                       formnames=['editsw', 'delsw'],
                       **kwargs)

        if [c.form, c.formname] == ['submit', 'delsw'] and c.delsw:
            h.redirect_url(h.url_titleindex)

        # Setup context for page generation
        c.urldir = swurl and swurl[-1] == '/'
        c.swurl = swurl
        c.swiki = syscomp.get_staticwiki(swurl)
        c.title = c.swurl.split('/')[-1]

        html = ''
        if c.errmsg:
            html = self.returnerrmsg(environ)

        elif c.jsonobj and c.view == 'js':  # Ajax request <JSON>
            html = self.handlejson(environ)

        elif c.textobj and c.view == 'text':  # Ajax request <TEXT>
            html = self.handletext(environ)

        elif self._publicfile(c.swurl):  # Check for public file
            html = ''

        elif c.view == 'js':  # Ajax view, so empty html
            html = ''

        elif c.editsw and c.swiki:  # Page-logic, edit static wiki
            c.wikitypenames = wikicomp.typenames
            c.title = '%s:edit' % c.title
            html = render('/derived/home/guestwiki.html')

        elif c.swiki and (c.swiki.type.wiki_typename == h.WIKITYPE_REDIRECT) \
                and c.swiki.sourceurl :         # Page redirect
            h.redirect_url(c.swiki.sourceurl)

        elif c.urldir:  # List static wiki directory
            c.swikis = self.listswdir()
            c.swa = ca.get_analyticobj('staticwiki')
            c.swsnippets = getattr(c.swa, 'pagesnippets', {})
            html = render('/derived/home/guestwiki.html')

        elif c.swiki:  # Page-logic, show static wiki
            if not c.swiki.texthtml:
                c.swhtml = c.swiki.translate(wiki=c.swiki, cache=True)
            elif c.refresh:
                c.swhtml = c.swiki.translate(wiki=c.swiki, cache=True)
            else:
                c.swhtml = c.swiki.texthtml
            html = render('/derived/home/guestwiki.html')

        elif h.authorized(h.HasPermname('STATICWIKI_CREATE')):
            # Assume this as a new static wiki url and create it.
            c.wikitypenames = wikicomp.typenames
            c.swiki = syscomp.set_staticwiki(unicode(swurl),
                                             u'',
                                             byuser=c.authuser)
            c.editsw = 1
            html = render('/derived/home/guestwiki.html')

        else:
            raise NotAuthorizedError(
                'You are allowed to create this resource.')

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

    def __after__(self):
        """Called calling any actions under this controller"""
        self.aftercontrollers()  # Genering, app-level after-controller handler