You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by gj...@apache.org on 2012/05/04 19:08:00 UTC
svn commit: r1334065 - in
/incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct:
templates/product_delete.html templates/product_edit.html
templates/product_list.html templates/product_view.html web_ui.py
Author: gjm
Date: Fri May 4 17:07:59 2012
New Revision: 1334065
URL: http://svn.apache.org/viewvc?rev=1334065&view=rev
Log:
products: basic list, view, create and edit pages for products #37
Added:
incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html (with props)
incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html (with props)
incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html (with props)
incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html (with props)
Modified:
incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/web_ui.py
Added: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html?rev=1334065&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html (added)
+++ incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html Fri May 4 17:07:59 2012
@@ -0,0 +1,30 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+ <head>
+ <title>Delete Product ${product.name}</title>
+ </head>
+
+ <body>
+ <div id="content" class="product">
+ <h1>Delete Product ${product.name}</h1>
+
+ <form id="edit" action="" method="post">
+ <div>
+ <input type="hidden" name="action" value="delete" />
+ <p><strong>Are you sure you want to delete this product?</strong></p>
+ </div>
+ <div class="buttons">
+ <input type="submit" name="cancel" value="${_('Cancel')}" />
+ <input type="submit" value="${_('Delete product')}" />
+ </div>
+ </form>
+
+ </div>
+ </body>
+</html>
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_delete.html
------------------------------------------------------------------------------
svn:mime-type = text/html
Added: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html?rev=1334065&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html (added)
+++ incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html Fri May 4 17:07:59 2012
@@ -0,0 +1,49 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+ <head>
+ <py:choose test="product._exists">
+ <title py:when="True">Edit Product ${product.name}</title>
+ <title py:otherwise="">New Product</title>
+ </py:choose>
+ </head>
+
+ <body>
+ <div id="content" class="product">
+ <py:choose test="product._exists">
+ <h1 py:when="True">Edit Product ${product.name}</h1>
+ <h1 py:otherwise="">New Product</h1>
+ </py:choose>
+
+ <form id="edit" action="" method="post">
+ <div class="field">
+ <input type="hidden" name="action" value="edit" />
+ <label>Short name for the product (prefix):<br />
+ <input type="text" id="prefix" name="prefix" size="32" value="${product.prefix or req.args.get('prefix')}" readonly="${product._exists and 'readonly'}"/>
+ </label>
+ <label>Name of the product:<br />
+ <input type="text" id="name" name="name" size="32" value="${product.name or req.args.get('name')}" />
+ </label>
+ </div>
+ <div class="field">
+ <fieldset class="iefix">
+ <label for="description" i18n:msg="">Description (you may use <a tabindex="42"
+ href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here):</label>
+ <p><textarea id="description" name="description" class="wikitext trac-resizable" rows="10" cols="78">
+${product.description}</textarea></p>
+ </fieldset>
+ </div>
+ <div class="buttons" py:choose="product._exists">
+ <input py:when="True" type="submit" value="${_('Submit changes')}" />
+ <input py:otherwise="" type="submit" value="${_('Add Product')}" />
+ <input type="submit" name="cancel" value="${_('Cancel')}" />
+ </div>
+ </form>
+ </div>
+ </body>
+</html>
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_edit.html
------------------------------------------------------------------------------
svn:mime-type = text/html
Added: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html?rev=1334065&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html (added)
+++ incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html Fri May 4 17:07:59 2012
@@ -0,0 +1,42 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+ <head>
+ <title>Products</title>
+ </head>
+
+ <body>
+ <div id="content" class="products">
+ <h1>Products</h1>
+
+ <div class="products">
+ <div py:for="product in products" class="product">
+
+ <div class="info trac-progress">
+ <h2><a href="${href.products(product.prefix)}">
+ Product: <em>${product.name}</em>
+ </a></h2>
+ </div>
+
+ <div class="description" xml:space="preserve">
+ ${wiki_to_html(context.child(product.resource), product.description)}
+ </div>
+
+ </div>
+ </div>
+
+ <div py:if="'PRODUCT_CREATE' in perm" class="buttons">
+ <form method="get" action="${href.products()}"><div>
+ <input type="hidden" name="action" value="new" />
+ <input type="submit" value="${_('Add new product')}" />
+ </div></form>
+ </div>
+
+ </div>
+ </body>
+</html>
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_list.html
------------------------------------------------------------------------------
svn:mime-type = text/html
Added: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html?rev=1334065&view=auto
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html (added)
+++ incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html Fri May 4 17:07:59 2012
@@ -0,0 +1,41 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+ <head>
+ <title>Product ${product.name}</title>
+ <link py:if="'PRODUCT_MODIFY' in perm(product.resource)" rel="alternate" type="application/x-wiki"
+ title="Edit this product" href="${href.products(product.prefix, action='edit')}" />
+ </head>
+
+ <body>
+ <div id="content" class="product">
+ <h1>Product ${product.name}</h1>
+ <div class="description" xml:space="preserve">
+ ${wiki_to_html(context, product.description)}
+ </div>
+
+ <div py:if="'PRODUCT_MODIFY' in perm(product.resource) or
+ 'PRODUCT_DELETE' in perm(product.resource)"
+ class="buttons">
+ <form py:if="'PRODUCT_MODIFY' in perm(product.resource)" method="get" action="" id="editproduct">
+ <div>
+ <input type="hidden" name="action" value="edit" />
+ <input type="submit" value="${_('Edit product')}" />
+ </div>
+ </form>
+ <form py:if="'PRODUCT_DELETE' in perm(product.resource)" method="get" action="" id="deleteproduct">
+ <div>
+ <input type="hidden" name="action" value="delete" />
+ <input type="submit" value="${_('Delete product')}" />
+ </div>
+ </form>
+ </div>
+
+ </div>
+ </body>
+</html>
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/templates/product_view.html
------------------------------------------------------------------------------
svn:mime-type = text/html
Modified: incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/web_ui.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/web_ui.py?rev=1334065&r1=1334064&r2=1334065&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/web_ui.py (original)
+++ incubator/bloodhound/trunk/bloodhound_multiproduct/multiproduct/web_ui.py Fri May 4 17:07:59 2012
@@ -22,7 +22,11 @@ Provides request filtering to capture pr
"""
import re
+from genshi.builder import tag
+
from trac.core import Component, implements, TracError
+from trac.web.chrome import (add_link, add_notice, add_warning, prevnext_nav,
+ Chrome, INavigationContributor)
from trac.resource import ResourceNotFound
from trac.util.translation import _
from trac.web.api import IRequestFilter, IRequestHandler, Request, HTTPNotFound
@@ -35,7 +39,15 @@ PRODUCT_RE = re.compile(r'^/products/(?P
class ProductModule(Component):
"""Base Product behaviour"""
- implements(IRequestFilter, IRequestHandler)
+ implements(IRequestFilter, IRequestHandler, INavigationContributor)
+
+ def get_active_navigation_item(self, req):
+ return 'products'
+
+ def get_navigation_items(self, req):
+ if 'PRODUCT_VIEW' in req.perm:
+ yield ('mainnav', 'products',
+ tag.a(_('Products'), href=req.href.products(), accesskey=3))
# IRequestFilter methods
def pre_process_request(self, req, handler):
@@ -95,9 +107,137 @@ class ProductModule(Component):
def process_request(self, req):
"""process request handler"""
- if req.args.get('productid', None):
- return 'product.html', None, None
- return 'product_list.html', None, None
+
+ req.perm.require('PRODUCT_VIEW')
+ pid = req.args.get('productid', None)
+ action = req.args.get('action', 'view')
+
+ products = [p for p in Product.select(self.env)
+ if 'PRODUCT_VIEW' in req.perm(p.resource)]
+
+ if pid is not None:
+ add_link(req, 'up', req.href.products(), _('Products'))
+
+ try:
+ product = Product(self.env, {'prefix': pid})
+ except ResourceNotFound:
+ product = Product(self.env)
+
+ data = {'product': product}
+
+ if req.method == 'POST':
+ if req.args.has_key('cancel'):
+ req.redirect(req.href.products(product.prefix))
+ elif action == 'edit':
+ return self._do_save(req, product)
+ elif action == 'delete':
+ req.perm(product.resource).require('PRODUCT_DELETE')
+ retarget_to = req.args.get('retarget', None)
+ name = product.name
+ product.delete(resources_to=retarget_to)
+ add_notice(req, _('The product "%(n)s" has been deleted.',
+ n = name))
+ req.redirect(req.href.products())
+ elif action in ('new', 'edit'):
+ return self._render_editor(req, product)
+ elif action == 'delete':
+ req.perm(product.resource).require('PRODUCT_DELETE')
+ return 'product_delete.html', data, None
+
+ if pid is None:
+ data = {'products': products}
+ return 'product_list.html', data, None
+
+ def add_product_link(rel, product):
+ href = req.href.products(product.prefix)
+ add_link(req, rel, href, _('Product "%(name)s"',
+ name=product.name))
+
+ idx = [i for i, p in enumerate(products) if p.name == product.name]
+ if idx:
+ idx = idx[0]
+ if idx > 0:
+ add_product_link('first', products[0])
+ add_product_link('prev', products[idx - 1])
+ if idx < len(products) - 1:
+ add_product_link('next', products[idx + 1])
+ add_product_link('last', products[-1])
+ prevnext_nav(req, _('Previous Product'), _('Next Product'),
+ _('Back to Product List'))
+ return 'product_view.html', data, None
+
+ def _render_editor(self, req, product):
+ """common processing for creating rendering the edit page"""
+ if product._exists:
+ req.perm(product.resource).require('PRODUCT_MODIFY')
+ else:
+ req.perm(product.resource).require('PRODUCT_CREATE')
+
+ chrome = Chrome(self.env)
+ chrome.add_jquery_ui(req)
+ chrome.add_wiki_toolbars(req)
+ data = {'product': product}
+ return 'product_edit.html', data, None
+
+ def _do_save(self, req, product):
+ """common processing for product save events"""
+ req.perm.require('PRODUCT_VIEW')
+
+ name = req.args.get('name')
+ prefix = req.args.get('prefix')
+ description = req.args.get('description','')
+
+ owner = req.args.get('owner')
+ keys = {'prefix':prefix}
+ field_data = {'name':name,
+ 'description':description,
+ 'owner':owner,
+ }
+
+ warnings = []
+ def warn(msg):
+ add_warning(req, msg)
+ warnings.append(msg)
+
+ if product._exists:
+ if name != product.name and Product.select(self.env,
+ where={'name':name}):
+ warn(_('A product with name "%(name)s" already exists, please '
+ 'choose a different name.', name=name))
+ elif not name:
+ warn(_('You must provide a name for the product.'))
+ else:
+ req.perm.require('PRODUCT_MODIFY')
+ product.update_field_dict(field_data)
+ product.update()
+ add_notice(req, _('Your changes have been saved.'))
+ else:
+ req.perm.require('PRODUCT_CREATE')
+
+ if not prefix:
+ warn(_('You must provide a prefix for the product.'))
+ elif Product.select(self.env, where={'prefix':prefix}):
+ warn(_('Product "%(id)s" already exists, please choose another '
+ 'prefix.', id=prefix))
+ if not name:
+ warn(_('You must provide a name for the product.'))
+ elif Product.select(self.env, where={'name':name}):
+ warn(_('A product with name "%(name)s" already exists, please '
+ 'choose a different name.', name=name))
+
+ if not warnings:
+ prod = Product(self.env)
+ prod.update_field_dict(keys)
+ prod.update_field_dict(field_data)
+ prod.insert()
+ add_notice(req, _('The product "%(id)s" has been added.',
+ id=prefix))
+ if warnings:
+ product.update_field_dict(keys)
+ product.update_field_dict(field_data)
+ return self._render_editor(req, product)
+ req.redirect(req.href.products(prefix))
+
# helper methods for INavigationContributor implementations
@classmethod