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()
+
+