/ interfaces / web / web.py
web.py
  1  from datetime import datetime
  2  from urllib import urlencode
  3  
  4  from jinja2 import Environment, FileSystemLoader
  5  import cherrypy
  6  
  7  from libbe import storage
  8  from libbe import bugdir
  9  from libbe.command.depend import get_blocked_by, get_blocks
 10  from libbe.command.target import add_target, remove_target
 11  from libbe.command.target import bug_from_target_summary, bug_target
 12  from libbe.command.util import bugdir_bug_comment_from_user_id
 13  from libbe.storage.util import settings_object
 14  import libbe.command.tag
 15  
 16  
 17  EMPTY = settings_object.EMPTY
 18  
 19  def datetimeformat(value, format='%B %d, %Y at %I:%M %p'):
 20      """Takes a timestamp and revormats it into a human-readable string."""
 21      return datetime.fromtimestamp(value).strftime(format)
 22  
 23  
 24  class WebInterface:
 25      """The web interface to CFBE."""
 26  
 27      def __init__(self, bug_root, template_root):
 28          """Initialize the bug repository for this web interface."""
 29          self.bug_root = bug_root
 30          store = storage.get_storage(self.bug_root)
 31          store.connect()
 32          version = store.storage_version()
 33          print version
 34          self.bd = bugdir.BugDir(store, from_storage=True)
 35          self.repository_name = self.bug_root.split('/')[-1]
 36          self.env = Environment(loader=FileSystemLoader(template_root))
 37          self.env.filters['datetimeformat'] = datetimeformat
 38  
 39      def get_common_information(self):
 40          """Returns a dict of common information that most pages will need."""
 41          possible_assignees = list(set(
 42            [unicode(bug.assigned) for bug in self.bd if bug.assigned != EMPTY]))
 43          possible_assignees.sort(key=unicode.lower)
 44  
 45          possible_targets = list(set(
 46            [unicode(bug.summary.rstrip("\n")) for bug in self.bd \
 47                  if bug.severity == u"target"]))
 48  
 49          possible_targets.sort(key=unicode.lower)
 50  
 51          possible_statuses = [u'open', u'assigned', u'test', u'unconfirmed',
 52                               u'closed', u'disabled', u'fixed', u'wontfix']
 53  
 54          possible_severities = [u'minor', u'serious', u'critical', u'fatal',
 55                                 u'wishlist']
 56  
 57          return {'possible_assignees': possible_assignees,
 58                  'possible_targets': possible_targets,
 59                  'possible_statuses': possible_statuses,
 60                  'possible_severities': possible_severities,
 61                  'tags': libbe.command.tag.get_all_tags(self.bd),
 62                  'repository_name': self.repository_name,}
 63  
 64      def filter_bugs(self, status, assignee, target, tag):
 65          """Filter the list of bugs to return only those desired."""
 66          bugs = [bug for bug in self.bd if bug.status in status]
 67  
 68          if assignee != '':
 69              assignee = None if assignee == 'None' else assignee
 70              bugs = [bug for bug in bugs if bug.assigned == assignee]
 71  
 72          if tag != '' and tag != 'None':
 73              bugs = [bug for bug in bugs
 74                      if tag in libbe.command.tag.get_tags(bug)]
 75  
 76          if target != '':
 77              target = None if target == 'None' else target
 78              if target == None:
 79                  # Return all bugs that don't block any targets.
 80                  return [bug for bug in bugs if not bug_target(self.bd, bug)]
 81              else:
 82                  # Return all bugs that block the supplied target.
 83                  targetbug = bug_from_target_summary(self.bd, target)
 84                  if targetbug == None:
 85                      return []
 86                  bugs = [bug for bug in get_blocked_by(self.bd, targetbug) if
 87                          bug.active]
 88  
 89          return bugs
 90  
 91  
 92      @cherrypy.expose
 93      def index(self, status='open', assignee='', target='', tag=''):
 94          """The main bug page.
 95          Bugs can be filtered by assignee or target.
 96          The bug database will be reloaded on each visit."""
 97  
 98          self.bd.load_all_bugs()
 99  
100          if status == 'open':
101              status = ['open', 'assigned', 'test', 'unconfirmed', 'wishlist']
102              label = 'All Open Bugs'
103          elif status == 'closed':
104              status = ['closed', 'disabled', 'fixed', 'wontfix']
105              label = 'All Closed Bugs'
106  
107          if assignee != '':
108              label += ' Currently Unassigned' if assignee == 'None' \
109                  else ' Assigned to %s' % (assignee,)
110          if target != '':
111              label += ' Currently Unscheduled' if target == 'None' \
112                  else ' Scheduled for %s' % (target,)
113          if tag != '' and tag != 'None':
114              label += ' Tagged %s' % (tag,)
115  
116          bugs = self.filter_bugs(status, assignee, target, tag)
117          if len(bugs) == 0:
118              template = self.env.get_template('empty-list.html')
119          else:
120              template = self.env.get_template('list.html')
121  
122          common_info = self.get_common_information()
123          return template.render(bugs=bugs, bd=self.bd, label=label,
124                                 assignees=common_info['possible_assignees'],
125                                 targets=common_info['possible_targets'],
126                                 statuses=common_info['possible_statuses'],
127                                 severities=common_info['possible_severities'],
128                                 repository_name=common_info['repository_name'],
129                                 tags=common_info['tags'],
130                                 urlencode=urlencode)
131  
132  
133      @cherrypy.expose
134      def bug(self, id=''):
135          """The page for viewing a single bug."""
136  
137          self.bd.load_all_bugs()
138  
139          bugdir, bug, comment = bugdir_bug_comment_from_user_id(
140              {self.bd.uuid: self.bd}, id)
141  
142          template = self.env.get_template('bug.html')
143          common_info = self.get_common_information()
144  
145          # Determine which targets a bug has.
146          # First, is this bug blocking any other bugs?
147          targets = ''
148          blocks = get_blocks(self.bd, bug)
149          for targetbug in blocks:
150              # Are any of those blocked bugs targets?
151              blocker = self.bd.bug_from_uuid(targetbug.uuid)
152              if blocker.severity == "target":
153                  targets += "%s " % blocker.summary
154  
155          return template.render(bug=bug, bd=self.bd,
156                                 assignee='' if bug.assigned == EMPTY else bug.assigned,
157                                 target=targets,
158                                 assignees=common_info['possible_assignees'],
159                                 targets=common_info['possible_targets'],
160                                 statuses=common_info['possible_statuses'],
161                                 severities=common_info['possible_severities'],
162                                 repository_name=common_info['repository_name'])
163  
164  
165      @cherrypy.expose
166      def create(self, summary):
167          """The view that handles the creation of a new bug."""
168          if summary.strip() != '':
169              self.bd.new_bug(summary=summary).save()
170          raise cherrypy.HTTPRedirect('/', status=302)
171  
172  
173      @cherrypy.expose
174      def comment(self, id, body):
175          """The view that handles adding a comment."""
176          bug = self.bd.bug_from_uuid(id)
177  
178          if body.strip() != '':
179              bug.comment_root.new_reply(body=body)
180              bug.save()
181  
182          raise cherrypy.HTTPRedirect(
183              '/bug?%s' % urlencode({'id':bug.id.long_user()}),
184              status=302)
185  
186      @cherrypy.expose
187      def edit(self, id, status=None, target=None, assignee=None, severity=None, summary=None):
188          """The view that handles editing bug details."""
189          bug = self.bd.bug_from_uuid(id)
190  
191          if summary != None:
192              bug.summary = summary
193          else:
194              bug.status = status if status != 'None' else None
195              bug.assigned = assignee if assignee != 'None' else None
196              bug.severity = severity if severity != 'None' else None
197  
198          if target:
199              current_target = bug_target(self.bd, bug)
200              if current_target:
201                  remove_target(self.bd, bug)
202                  if target != "None":
203                      add_target(self.bd, bug, target)
204              else:
205                  add_target(self.bd, bug, target)
206  
207          bug.save()
208  
209          raise cherrypy.HTTPRedirect(
210              '/bug?%s' % urlencode({'id':bug.id.long_user()}),
211              status=302)