You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by ah...@apache.org on 2013/07/28 02:33:18 UTC

svn commit: r1507750 - in /bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding: api.py templates/bh_emb_milestone.html templates/bh_emb_product.html templates/bh_emb_ticket.html tests/api.py

Author: ahorincar
Date: Sun Jul 28 00:33:17 2013
New Revision: 1507750

URL: http://svn.apache.org/r1507750
Log:
Finished retrieving information about tickets, milestones and products

Modified:
    bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/api.py
    bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_milestone.html
    bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_product.html
    bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_ticket.html
    bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/tests/api.py

Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/api.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/api.py?rev=1507750&r1=1507749&r2=1507750&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/api.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/api.py Sun Jul 28 00:33:17 2013
@@ -6,58 +6,158 @@ from trac.web.chrome import ITemplatePro
 from trac.web.main import IRequestHandler
 from trac.perm import IPermissionRequestor, PermissionCache, PermissionSystem
 from trac.util import escape, Markup
-from trac.core import Component, implements
+from trac.core import Component, TracError, implements
 from trac.ticket import model
 from trac.core import TracError
-from trac.ticket.model import Ticket, Milestone
+from trac.ticket.model import Ticket, Milestone, MilestoneCache, Version, Component as component
 from trac.ticket.web_ui import TicketModule
 from trac.ticket.api import TicketSystem
+from trac.ticket.query import Query, QueryModule, TicketQueryMacro, QueryValueError, QuerySyntaxError
 from multiproduct.model import Product
 from multiproduct.web_ui import ProductModule
+from multiproduct.ticket import query
 from trac.resource import Resource, ResourceNotFound
+from trac.ticket.roadmap import get_tickets_for_milestone
+from trac.attachment import Attachment
 
 
+from multiproduct.env import ProductEnvironment
+
+from multiproduct.ticket.web_ui import ProductTicketModule
+
 class EmbeddingSystem(Component):
     implements(IRequestHandler, IPermissionRequestor, ITemplateProvider)
 
-
     # IPermissionRequestor method
     def get_permission_actions(self):
         return ['TICKET_VIEW', 'MILESTONE_VIEW', 'PRODUCT_VIEW']
 
+    def get_tickets_for_product(self, env, product=''):
+        """Retrieve all tickets associated with the product."""
+        q = query.ProductQuery.from_string(env, 'product=%s' % product)
+        return q.execute()
+
+
+    def changeLog(self, id):
+        t = Ticket(self.env, id)
+        for date, author, field, old, new, permanent in t.get_changelog():
+            yield (date, author, field, old, new, permanent)
+
+
+    def query(self, req, qstr='status!=closed'):
+        q = query.ProductQuery.from_string(self.env, qstr)
+        ticket_realm = Resource('ticket')
+        out = []
+        for t in q.execute(req):
+            tid = t['id']
+            if 'TICKET_VIEW' in req.perm(ticket_realm(id=tid)):
+                out.append(tid)
+        return out
+
+    def get_attachments(self, realm, id):
+        return [a.filename for a in Attachment.select(self.env, realm, id)]
+
 
     # IRequestHandler methods
-    def match_request(self, req):
-        embed_re = re.compile(r'^/api/(?P<resource_name>[^/]*)/(?P<resource_key>[^/]*)$')
-        match = embed_re.match(req.path_info)
 
-        if match:
-            req.args['resource_name'] = match.group('resource_name')
-            req.args['resource_key'] = match.group('resource_key')
-        return not match is None
+    def match_request(self, req):
+        if re.match(r'/api/ticket/([0-9]+)$', req.path_info):
+            match = re.match(r'/api/(ticket)/([0-9]+)$', req.path_info)
+            req.args['name'] = match.group(1)
+            req.args['id'] = match.group(2)
+            return True
+        elif re.match(r'/api/milestone/(.+)$', req.path_info):
+            match = re.match(r'/api/(milestone)/(.+)$', req.path_info)
+            req.args['name'] = match.group(1)
+            req.args['id'] = match.group(2)
+            return True
+        elif re.match(r'/api/products/(.+)$', req.path_info):
+            match = re.match(r'/api/(products)/(.+)$', req.path_info)
+            req.args['name'] = match.group(1)
+            req.args['id'] = match.group(2)
+            return True
+        elif req.path_info == '/api/query':
+            req.args['name'] = 'query'
+            return True
 
 
     def process_request(self, req):
-        resource = req.args.get('resource_name')
-        key = req.args.get('resource_key')
-
-        if resource == 'ticket':
-            req.perm.require('TICKET_MODIFY')
-            data = {'ticket': Ticket(self.env, key)}
+        name = req.args.get('name')
+        if not (name == 'query'):
+            id = req.args.get('id')
+
+        if name == 'ticket':
+            req.perm.require('TICKET_VIEW')
+            comm_num = 0
+            attachment_num = len(self.get_attachments('ticket', id))
+            ticket_log = self.changeLog(id)
+            for log in ticket_log:
+                if log[2] == 'comment' and log[4]:
+                    comm_num += 1
+
+            data = {'ticket': Ticket(self.env, id),
+                    'comm_num': comm_num,
+                    'attachment_num': attachment_num}
             return 'bh_emb_ticket.html', data, None
-        elif resource == 'milestone':
-            req.perm.require('MILESTONE_MODIFY')
-            data = {'milestone': Milestone(self.env, key)}
+
+        elif name == 'milestone':
+            req.perm.require('MILESTONE_VIEW')
+            ticket_num = len(get_tickets_for_milestone(self.env, milestone=id))
+            attachment_num = len(self.get_attachments('milestone', id))
+            data = {'milestone': Milestone(self.env, id),
+                    'product': self.env.product,
+                    'ticket_number': ticket_num,
+                    'attachment_number': attachment_num }
             return 'bh_emb_milestone.html', data, None
-        elif resource == 'products':
-            req.perm.require('PRODUCT_MODIFY')
-            data = {'product': Product(self.env, {'prefix': key})}
+
+        elif name == 'products':
+            req.perm.require('PRODUCT_VIEW')
+            product = Product(self.env, {'prefix': id})
+            ticket_num = len(self.get_tickets_for_product(self.env, id))
+            product_env = ProductEnvironment(self.env, product.prefix)
+            milestone_num = len(Milestone.select(product_env))
+            version_num = len(Version.select(product_env))
+            components = component.select(product_env)
+            component_num = 0
+            for c in components:
+                component_num += 1
+
+            data = {'product': product,
+                    'ticket_num': ticket_num,
+                    'owner': product.owner,
+                    'milestone_num': milestone_num,
+                    'version_num': version_num,
+                    'component_num': component_num}
             return 'bh_emb_product.html', data, None
+        elif name == 'query':
+            # Feature not yet finished
+            qstring = req.query_string
+            if qstring == '':
+                if req.authname and req.authname != 'anonymous':
+                    default_query = QueryModule.default_query
+                    qstring = default_query.default
+                    user = req.authname
+                else:
+                    email = req.session.get('email')
+                    name = req.session.get('name')
+                    default_anonymous_query = QueryModule.default_anonymous_query
+                    qstring = default_anonymous_query.default
+                    user = email or name or None
+
+            query_results = self.query(req, qstring)
+            print "Query results:"
+            print query
+            for r in query_results:
+                ticket = Ticket(self.env, r)
+                if ticket.product == self.env.product.prefix:
+                    print q
+
+            data = {}
+            return 'bh_emb_query.html', data, None
         else:
-            msg = "Resource does not exist."
+            msg = "It is not possible to embed this resource."
             raise ResourceNotFound((msg), ("Invalid resource"))
 
-# Check for when the fields are not filled in
 
     ### ITemplateProvider methods
 
@@ -66,6 +166,4 @@ class EmbeddingSystem(Component):
         return [resource_filename('bhembedding', 'templates')]
 
     def get_htdocs_dirs(self):
-        return [] # temporarily, since there are no html docs yet
-        # from pkg_resources import resource_filename
-        # return [('ticket', resource_filename('bhembedding', 'htdocs'))]
+        return []

Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_milestone.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_milestone.html?rev=1507750&r1=1507749&r2=1507750&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_milestone.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_milestone.html Sun Jul 28 00:33:17 2013
@@ -6,11 +6,13 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:i18n="http://genshi.edgewall.org/i18n">
   <xi:include href="layout.html" />
+
   <head>
-    <title>Milestone</title>
+    <title>Milestone ${milestone.name}</title>
   </head>
+
   <body>
-    <h2>Milestone ${milestone.name}</h2>
+    <h2><a href="${href.milestone(milestone.name)}">${milestone.name}</a></h2>
     <py:choose>
       <p py:when="milestone.completed" class="date">
         <i18n:msg params="duration, date">
@@ -24,20 +26,13 @@
         <i18n:msg params="duration, date">
           <strong>Due in:</strong> ${dateinfo(milestone.due)} (${format_datetime(milestone.due)})
         </i18n:msg></p>
-      <p py:otherwise="" class="date">
-        No date set</p>
     </py:choose>
     <py:choose>
       <p py:when="milestone.description">
-          Description: ${milestone.description}</p>
-      <p py:otherwise="">
-        No description provided.</p>
+          <strong>Description:</strong> ${milestone.description}</p>
     </py:choose>
-
-
-    <p><strong>No. of tickets:</strong></p>
-    <p><strong>Attachments:</strong></p>
-
-
+    <p><strong>Product:</strong> ${product.name}</p>
+    <p><strong>Number of tickets:</strong> ${ticket_number}</p>
+    <p><strong>Attachments:</strong> ${attachment_number}</p>
   </body>
 </html>

Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_product.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_product.html?rev=1507750&r1=1507749&r2=1507750&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_product.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_product.html Sun Jul 28 00:33:17 2013
@@ -7,22 +7,23 @@
       xmlns:i18n="http://genshi.edgewall.org/i18n">
   <xi:include href="layout.html" />
   <head>
-    <title>Product</title>
+    <title>Product ${product.name}</title>
   </head>
   <body>
-    <h2>Product ${product.name}</h2>
+    <h2><a href="${href.products(product.prefix)}">${product.name}</a></h2>
     <py:choose>
       <p py:when="product.description">
-          <strong>Description:</strong> ${product.description}</p>
-      <p py:otherwise="">
-        No description provided.</p>
+        <strong>Description:</strong> ${product.description}
+      </p>
     </py:choose>
-
-    <p><strong>Owner:</strong></p>
-    <p><strong>No. of tickets:</strong></p>
-    <p><strong>No. of milestones:</strong></p>
-    <p><strong>No. of components:</strong></p>
-    <p><strong>No. of versions</strong></p>
-    
+    <py:choose>
+      <p py:when="owner">
+          <strong>Owner:</strong><a href="${href.query(owner=owner, status='!closed',order='priority')}">
+                                  ${owner}</a></p>
+    </py:choose>
+    <p><strong>Number of tickets:</strong> ${ticket_num}</p>
+    <p><strong>Number of milestones:</strong> ${milestone_num}</p>
+    <p><strong>Number of versions:</strong> ${version_num}</p>
+    <p><strong>Number of components:</strong> ${component_num}</p>
   </body>
 </html>

Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_ticket.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_ticket.html?rev=1507750&r1=1507749&r2=1507750&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_ticket.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/templates/bh_emb_ticket.html Sun Jul 28 00:33:17 2013
@@ -4,39 +4,60 @@
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:xi="http://www.w3.org/2001/XInclude"
       xmlns:py="http://genshi.edgewall.org/"
-      xmlns:i18n="http://genshi.edgewall.org/i18n"
-      py:with="preview_mode = 'preview' in req.args">
+      xmlns:i18n="http://genshi.edgewall.org/i18n">
   <xi:include href="layout.html" />
 
   <head>
     <title>Ticket ${ticket.id}</title>
   </head>
+
   <body>
     <div>
       <div>
-        <h2>Ticket ${ticket.id}</h2>
-        <p><strong>Summary:</strong> ${ticket.summary}</p>
+        <h2>${ticket.summary}</h2>
+        <p>
+          <a href="${href.ticket(ticket.id)}">Ticket ${ticket.id}</a>
+           - Assigned to
+          <a href="${href.query(owner=ticket.owner, status='!closed',
+              ticket=ticket.id, order='priority')}">${ticket.owner}</a>
+           , last modified ${pretty_dateinfo(ticket.changetime)}
+        </p>
+        <p><strong>Reporter:</strong> ${ticket.reporter}</p>
+        <py:choose>
+          <p py:when="ticket.keywords">
+           <strong>Keywords:</strong> ${ticket.keywords}</p>
+        </py:choose>
+        <p><strong>Type:</strong> ${ticket.type}</p>
+        <p><strong>Status:</strong> ${ticket.status}</p>
+        <py:choose>
+          <p py:when="ticket.priority">
+           <strong>Priority:</strong> ${ticket.priority}</p>
+        </py:choose>
         <p><strong>Product:</strong> ${ticket.product}</p>
         <py:choose>
           <p py:when="ticket.milestone">
             <strong>Milestone:</strong> ${ticket.milestone}</p>
-          <p py:otherwise="">
-            The ticket doesn't belong to any milestone.</p>
         </py:choose>
-        <p><strong>Component:</strong> ${ticket.component}</p>
-        <p><strong>Priority:</strong> ${ticket.priority}</p>
-        <p><strong>Last modified:</strong> ${pretty_dateinfo(ticket.changetime)}</p>
-        <py:choose>
-          <p py:when="ticket.version">
-            <strong>Version:</strong> ${ticket.version}</p>
-          <p py:otherwise="">
-            No version was provided.</p>
+        <py:choose>
+          <p py:when="ticket.milestone">
+           <strong>Component:</strong> ${ticket.component}</p>
+        </py:choose>
+        <py:choose>
+          <p py:when="ticket.milestone">
+           <strong>Version:</strong> ${ticket.version}</p>
+        </py:choose>
+        <py:choose>
+          <p py:when="ticket.severity">
+           <strong>Severity:</strong> ${ticket.severity}</p>
+        </py:choose>
+        <py:choose>
+          <p py:when="comm_num">
+           <strong>Number of comments:</strong> $comm_num</p>
+        </py:choose>
+        <py:choose>
+          <p py:when="attachment_num">
+           <strong>Number of attachments:</strong> ${attachment_num}</p>
         </py:choose>
-        <p><strong>Assigned to:</strong> ${ticket.owner}</p>
-        <p><strong>Status:</strong> ${ticket.status}</p>
-
-        <p><strong>No. of comments:</strong></p>        
-
       </div>
     </div>
   </body>

Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/tests/api.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/tests/api.py?rev=1507750&r1=1507749&r2=1507750&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/tests/api.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_embedding_plugin/bhembedding/tests/api.py Sun Jul 28 00:33:17 2013
@@ -4,8 +4,8 @@ import shutil
 from trac.test import EnvironmentStub, Mock, MockPerm
 from trac.core import TracError
 from trac.core import implements, Component
-from bhembedding.api import EmbeddingSystem
-
+# from bhembedding.api import EmbeddingSystem
+import bhembedding.api
 
 class EmbeddingSystemTestCase(unittest.TestCase):
 
@@ -16,3 +16,5 @@ class EmbeddingSystemTestCase(unittest.T
 
     def tearDown(self):
         self.env.reset_db()
+
+