aboutsummaryrefslogblamecommitdiffstats
path: root/interfaces/web/web.py
blob: ed87c788bd5dcc8bb47221d06e9a805a52d916d4 (plain) (tree)
1
2
3
4
5
6
7
8
9
                             
                                  

                                                
               
 
                         
                        
                                                           
                                                          
                                                                    
                                                              
                                              
                        
 
 

                             


                                                                          
 
 

                                    
 
                                                

                                                                   


                                                  
                      
                                                         
                                                           
                                                                      
                                                           
 

                                                                             
                                      

                                                                           
 
                                    

                                                             
 
                                            
 

                                                                       
 

                                                                       
 



                                                           
                                                                
                                                         
 
                                                         

                                                                   
 
                          
                                                               
                                                                    
 



                                                              

                                                         








                                                                            
                                   
 
                   

 
                    
                                                                   


                                                           
 
                               
 





                                                                            
 
                          

                                                                    
                        
                                                                   
                                                    

                                          
 
                                                              




                                                               
                                                   
                                                                  



                                                                             
                                                                              
                                                        
                                                   

 


                                                
 
                               
 

                                                               
 
                                                    
                                                   









                                                           

                                                   
                                                                                      
                                              




                                                                              

 





                                                              

 



                                                     
 


                                                 




                                                             



                                                                                             
 



                                                             

                                                                   
 
                  






                                                     
 
                  



                                                             
from datetime import datetime
from urllib.parse import urlencode

from jinja2 import Environment, FileSystemLoader
import cherrypy

from libbe import storage
from libbe import bugdir
from libbe.command.depend import get_blocked_by, get_blocks
from libbe.command.target import add_target, remove_target
from libbe.command.target import bug_from_target_summary, bug_target
from libbe.command.util import bugdir_bug_comment_from_user_id
from libbe.storage.util import settings_object
import libbe.command.tag


EMPTY = settings_object.EMPTY

def datetimeformat(value, format='%B %d, %Y at %I:%M %p'):
    """Takes a timestamp and revormats it into a human-readable string."""
    return datetime.fromtimestamp(value).strftime(format)


class WebInterface:
    """The web interface to CFBE."""

    def __init__(self, bug_root, template_root):
        """Initialize the bug repository for this web interface."""
        self.bug_root = bug_root
        store = storage.get_storage(self.bug_root)
        store.connect()
        version = store.storage_version()
        print(version)
        self.bd = bugdir.BugDir(store, from_storage=True)
        self.repository_name = self.bug_root.split('/')[-1]
        self.env = Environment(loader=FileSystemLoader(template_root))
        self.env.filters['datetimeformat'] = datetimeformat

    def get_common_information(self):
        """Returns a dict of common information that most pages will need."""
        possible_assignees = list(set(
          [str(bug.assigned) for bug in self.bd if bug.assigned != EMPTY]))
        possible_assignees.sort(key=str.lower)

        possible_targets = list(set(
          [str(bug.summary.rstrip("\n")) for bug in self.bd \
                if bug.severity == "target"]))

        possible_targets.sort(key=str.lower)

        possible_statuses = ['open', 'assigned', 'test', 'unconfirmed',
                             'closed', 'disabled', 'fixed', 'wontfix']

        possible_severities = ['minor', 'serious', 'critical', 'fatal',
                               'wishlist']

        return {'possible_assignees': possible_assignees,
                'possible_targets': possible_targets,
                'possible_statuses': possible_statuses,
                'possible_severities': possible_severities,
                'tags': libbe.command.tag.get_all_tags(self.bd),
                'repository_name': self.repository_name,}

    def filter_bugs(self, status, assignee, target, tag):
        """Filter the list of bugs to return only those desired."""
        bugs = [bug for bug in self.bd if bug.status in status]

        if assignee != '':
            assignee = None if assignee == 'None' else assignee
            bugs = [bug for bug in bugs if bug.assigned == assignee]

        if tag != '' and tag != 'None':
            bugs = [bug for bug in bugs
                    if tag in libbe.command.tag.get_tags(bug)]

        if target != '':
            target = None if target == 'None' else target
            if target == None:
                # Return all bugs that don't block any targets.
                return [bug for bug in bugs if not bug_target(self.bd, bug)]
            else:
                # Return all bugs that block the supplied target.
                targetbug = bug_from_target_summary(self.bd, target)
                if targetbug == None:
                    return []
                bugs = [bug for bug in get_blocked_by(self.bd, targetbug) if
                        bug.active]

        return bugs


    @cherrypy.expose
    def index(self, status='open', assignee='', target='', tag=''):
        """The main bug page.
        Bugs can be filtered by assignee or target.
        The bug database will be reloaded on each visit."""

        self.bd.load_all_bugs()

        if status == 'open':
            status = ['open', 'assigned', 'test', 'unconfirmed', 'wishlist']
            label = 'All Open Bugs'
        elif status == 'closed':
            status = ['closed', 'disabled', 'fixed', 'wontfix']
            label = 'All Closed Bugs'

        if assignee != '':
            label += ' Currently Unassigned' if assignee == 'None' \
                else ' Assigned to %s' % (assignee,)
        if target != '':
            label += ' Currently Unscheduled' if target == 'None' \
                else ' Scheduled for %s' % (target,)
        if tag != '' and tag != 'None':
            label += ' Tagged %s' % (tag,)

        bugs = self.filter_bugs(status, assignee, target, tag)
        if len(bugs) == 0:
            template = self.env.get_template('empty-list.html')
        else:
            template = self.env.get_template('list.html')

        common_info = self.get_common_information()
        return template.render(bugs=bugs, bd=self.bd, label=label,
                               assignees=common_info['possible_assignees'],
                               targets=common_info['possible_targets'],
                               statuses=common_info['possible_statuses'],
                               severities=common_info['possible_severities'],
                               repository_name=common_info['repository_name'],
                               tags=common_info['tags'],
                               urlencode=urlencode)


    @cherrypy.expose
    def bug(self, id=''):
        """The page for viewing a single bug."""

        self.bd.load_all_bugs()

        bugdir, bug, comment = bugdir_bug_comment_from_user_id(
            {self.bd.uuid: self.bd}, id)

        template = self.env.get_template('bug.html')
        common_info = self.get_common_information()

        # Determine which targets a bug has.
        # First, is this bug blocking any other bugs?
        targets = ''
        blocks = get_blocks(self.bd, bug)
        for targetbug in blocks:
            # Are any of those blocked bugs targets?
            blocker = self.bd.bug_from_uuid(targetbug.uuid)
            if blocker.severity == "target":
                targets += "%s " % blocker.summary

        return template.render(bug=bug, bd=self.bd,
                               assignee='' if bug.assigned == EMPTY else bug.assigned,
                               target=targets,
                               assignees=common_info['possible_assignees'],
                               targets=common_info['possible_targets'],
                               statuses=common_info['possible_statuses'],
                               severities=common_info['possible_severities'],
                               repository_name=common_info['repository_name'])


    @cherrypy.expose
    def create(self, summary):
        """The view that handles the creation of a new bug."""
        if summary.strip() != '':
            self.bd.new_bug(summary=summary).save()
        raise cherrypy.HTTPRedirect('/', status=302)


    @cherrypy.expose
    def comment(self, id, body):
        """The view that handles adding a comment."""
        bug = self.bd.bug_from_uuid(id)

        if body.strip() != '':
            bug.comment_root.new_reply(body=body)
            bug.save()

        raise cherrypy.HTTPRedirect(
            '/bug?%s' % urlencode({'id':bug.id.long_user()}),
            status=302)

    @cherrypy.expose
    def edit(self, id, status=None, target=None, assignee=None, severity=None, summary=None):
        """The view that handles editing bug details."""
        bug = self.bd.bug_from_uuid(id)

        if summary != None:
            bug.summary = summary
        else:
            bug.status = status if status != 'None' else None
            bug.assigned = assignee if assignee != 'None' else None
            bug.severity = severity if severity != 'None' else None

        if target:
            current_target = bug_target(self.bd, bug)
            if current_target:
                remove_target(self.bd, bug)
                if target != "None":
                    add_target(self.bd, bug, target)
            else:
                add_target(self.bd, bug, target)

        bug.save()

        raise cherrypy.HTTPRedirect(
            '/bug?%s' % urlencode({'id':bug.id.long_user()}),
            status=302)