You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@bloodhound.apache.org by Dammina Sahabandu <dm...@gmail.com> on 2014/06/19 08:16:27 UTC

Re: svn commit: r1603720 - in /bloodhound/branches/bep_0011_batch_create_tickets: bloodhound_theme/bhtheme/ bloodhound_theme/bhtheme/htdocs/js/ bloodhound_theme/bhtheme/templates/ trac/trac/ticket/

I have removed the changes that I had done in the existing templates and
instead implemented the ITemplateStreamFilter methods for that purpose. The
thing is currently the users can use this anywhere which has the wiki
formatting(requires to have the TICKET_CREATE permission). So I need to
control the places where the user can use this feature. And I need to
implement a method to get the users inputs before rendering this feature
(such as how many tickets that he is going to create and which fields that
he will want to add). So my next step will be to implement those things.


On Thu, Jun 19, 2014 at 7:05 AM, <da...@apache.org> wrote:

> Author: dammina
> Date: Thu Jun 19 06:05:23 2014
> New Revision: 1603720
>
> URL: http://svn.apache.org/r1603720
> Log:
> removed the changes in the existing templates. Implement the
> ITemplateStreamFilter methods instead.
>
> Removed:
>
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_empty_table.html
> Modified:
>
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/theme.js
>
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_query.html
>
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_wiki_view.html
>
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py
>
> bloodhound/branches/bep_0011_batch_create_tickets/trac/trac/ticket/model.py
>
> Modified:
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/theme.js
> URL:
> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/theme.js?rev=1603720&r1=1603719&r2=1603720&view=diff
>
> ==============================================================================
> ---
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/theme.js
> (original)
> +++
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/theme.js
> Thu Jun 19 06:05:23 2014
> @@ -126,8 +126,27 @@ $(function() {
>      }
>    }
>
> +  // Update QCT select fields on product change.
>    $('#field-product').change(function(e) {
>      set_qct_more_enabled($(this).val());
> +    $qct_form = $('#qct-form');
> +    var product = $qct_form.find('#field-product').val()
> +    if(product) {
> +      var form_token = $qct_form.find('input[name="__FORM_TOKEN"]').val();
> +      var fields_to_update = ['version', 'type'];
> +      $.post('update-menus', { product: product, __FORM_TOKEN: form_token,
> +          fields_to_update: fields_to_update }).done(function(data) {
> +        $.each(data, function(i, v) {
> +          $field = $('#field-' + i);
> +          $field.empty();
> +          $field.append('<option value="">Choose...</option>');
> +          $.each(v, function(i, v) {
> +            $field.append('<option value="' + v + '">' + v + '</option>');
> +          });
> +
> +        });
> +      });
> +    }
>    });
>
>    set_qct_more_enabled($('#field-product').val());
>
> Modified:
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_query.html
> URL:
> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_query.html?rev=1603720&r1=1603719&r2=1603720&view=diff
>
> ==============================================================================
> ---
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_query.html
> (original)
> +++
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_query.html
> Thu Jun 19 06:05:23 2014
> @@ -256,7 +256,7 @@
>          <hr />
>        </form>
>
> -         <div class="span12">
> +      <div class="span12">
>          <xi:include href="widget_query_results.html" />
>        </div>
>        <div py:if="tickets and batch_modify" class="span12">
> @@ -264,9 +264,6 @@
>            <xi:include href="bh_batch_modify.html" />
>          </div>
>        </div>
> -         <div class="span12">
> -        <xi:include href="bh_empty_table.html" />
> -      </div>
>
>        <div class="buttons span12"
>             py:with="edit = report_resource and 'REPORT_MODIFY' in
> perm(report_resource);
>
> Modified:
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_wiki_view.html
> URL:
> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_wiki_view.html?rev=1603720&r1=1603719&r2=1603720&view=diff
>
> ==============================================================================
> ---
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_wiki_view.html
> (original)
> +++
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/templates/bh_wiki_view.html
> Thu Jun 19 06:05:23 2014
> @@ -143,12 +143,6 @@
>                  <button class="btn" type="submit"
> name="rename_page_button">${_('Rename page')}</button>
>                </div>
>              </form>
> -                       <form method="get" style="display:inline"
> action="${href.query()}" id="batchcreate">
> -              <input type="hidden" name="actionticketbatchcreate"
> value="rename" />
> -              <div class="btn-group">
> -                <button class="btn" type="submit"
> name="batchcreate">${_('Batch Create')}</button>
> -              </div>
> -            </form>
>              <form method="get" style="display:inline" action="${href.wiki(
> page.name)}" py:if="page.exists and delete_perm">
>                <input type="hidden" name="action" value="delete" />
>                <input type="hidden" name="version" value="$page.version" />
>
> Modified:
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py
> URL:
> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py?rev=1603720&r1=1603719&r2=1603720&view=diff
>
> ==============================================================================
> ---
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py
> (original)
> +++
> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py
> Thu Jun 19 06:05:23 2014
> @@ -25,6 +25,8 @@ from genshi.builder import tag
>  from genshi.core import TEXT
>  from genshi.filters.transform import Transformer
>  from genshi.output import DocType
> +from genshi.core import Markup
> +from genshi import HTML
>
>  from trac.config import ListOption, Option
>  from trac.core import Component, TracError, implements
> @@ -619,19 +621,11 @@ class QuickCreateTicketDialog(Component)
>          try:
>              tm = self._get_ticket_module()
>              req.perm.require('TICKET_CREATE')
> -            if 'field_summary' in req.args:
> -                summary = req.args.pop('field_summary', '')
> -                desc = ""
> -                attrs = dict([k[6:], v] for k, v in req.args.iteritems()
> +            summary = req.args.pop('field_summary', '')
> +            desc = ""
> +            attrs = dict([k[6:], v] for k, v in req.args.iteritems()
>                           if k.startswith('field_'))
> -
> -                product, tid = self.create(req, summary, desc, attrs,
> True)
> -            elif 'field_summary' not in req.args:
> -                attrs = dict([k[6:], v] for k, v in req.args.iteritems()
> -                         if k.startswith('field_'))
> -                #new_tkts variable will contain the tickets that have
> been created as a batch
> -                #that information will be used to load the resultant
> query table
> -                product, tid, new_tkts = self.batch_create(req, attrs,
> True)
> +            product, tid = self.create(req, summary, desc, attrs, True)
>          except Exception, exc:
>              self.log.exception("BH: Quick create ticket failed %s" %
> (exc,))
>              req.send(str(exc), 'plain/text', 500)
> @@ -684,10 +678,282 @@ class QuickCreateTicketDialog(Component)
>                  self.log.exception("Failure sending notification on
> creation "
>                                     "of ticket #%s: %s" % (t.id, e))
>          return t['product'], t.id
> +
> +from pkg_resources import get_distribution
> +application_version = get_distribution('BloodhoundTheme').version
> +
>
> +################################################################################################################
> +
> +class BatchCreateTicketDialog(Component):
> +    implements(IRequestFilter, IRequestHandler, ITemplateStreamFilter)
> +    bct_fields = ListOption('ticket', 'batch_create_fields',
> +                            'product, version, type',
> +        doc="""Multiple selection fields displayed in create ticket
> menu""",
> +                            doc_domain='bhtheme')
> +
> +    def __init__(self, *args, **kwargs):
> +        import pkg_resources
> +        locale_dir = pkg_resources.resource_filename(__name__, 'locale')
> +        add_domain(self.env.path, locale_dir)
> +        super(BatchCreateTicketDialog, self).__init__(*args, **kwargs)
> +
> +    # IRequestFilter(Interface):
> +
> +    def pre_process_request(self, req, handler):
> +        """Nothing to do.
> +        """
> +        return handler
> +
> +    def post_process_request(self, req, template, data, content_type):
> +        """Append necessary ticket data
> +        """
> +        try:
> +            tm = self._get_ticket_module()
> +        except TracError:
> +            # no ticket module so no create ticket button
> +            return template, data, content_type
> +
> +        if (template, data, content_type) != (None,) * 3:  # TODO: Check !
> +            if data is None:
> +                data = {}
> +            dum_req = dummy_request(self.env)
> +            dum_req.perm = req.perm
> +            ticket = Ticket(self.env)
> +            tm._populate(dum_req, ticket, False)
> +            all_fields = dict([f['name'], f]
> +                              for f in tm._prepare_fields(dum_req, ticket)
> +                              if f['type'] == 'select')
> +
> +            product_field = all_fields.get('product')
> +            if product_field:
> +                # When at product scope, set the default selection to the
> +                # product at current scope. When at global scope the
> default
> +                # selection is determined by [ticket] default_product
> +                if self.env.product and \
> +                        self.env.product.prefix in
> product_field['options']:
> +                    product_field['value'] = self.env.product.prefix
> +                # Transform the options field to dictionary of product
> +                # attributes and filter out products for which user
> doesn't
> +                #  have TICKET_CREATE permission
> +                product_field['options'] = [
> +                    dict(value=p,
> +                         new_ticket_url=dum_req.href.products(p,
> 'newticket'),
> +
> description=ProductEnvironment.lookup_env(self.env, p)
> +                                                       .product.name
> +                    )
> +                for p in product_field['options']
> +                    if req.perm.has_permission('TICKET_CREATE',
> +                                               Neighborhood('product', p)
> +                                               .child(None, None))]
> +            else:
> +                msg = _("Missing ticket field '%(field)s'.",
> field='product')
> +                if ProductTicketModule is not None and \
> +                        self.env[ProductTicketModule] is not None:
> +                    # Display warning alert to users
> +                    add_warning(req, msg)
> +                else:
> +                    # Include message in logs since this might be a
> failure
> +                    self.log.warning(msg)
> +            data['bct'] = {
> +                'fields': [all_fields[k] for k in self.bct_fields
> +                           if k in all_fields],
> +                'hidden_fields': [all_fields[k] for k in all_fields.keys()
> +                                  if k not in self.bct_fields] }
> +        return template, data, content_type
> +
> +    # IRequestHandler methods
> +
> +    def match_request(self, req):
> +        """Handle requests sent to /bct
> +        """
> +        m = PRODUCT_RE.match(req.path_info)
> +        return req.path_info == '/bct' or \
> +            (m and m.group('pathinfo').strip('/') == 'bct')
> +
> +    def process_request(self, req):
> +
> +        self.log.debug("BatchCreateTicketsModule: process_request
> entered")
> +        """Forward new ticket request to `trac.ticket.web_ui.TicketModule`
> +        but return plain text suitable for AJAX requests.
> +        """
> +        try:
> +            tm = self._get_ticket_module()
> +            req.perm.require('TICKET_CREATE')
> +
> +            attrs = dict([k[6:], v] for k, v in req.args.iteritems()
> +                         if k.startswith('field_'))
> +            #new_tkts variable will contain the tickets that have been
> created as a batch
> +            #that information will be used to load the resultant query
> table
> +            product, tid, new_tkts = self.batch_create(req, attrs, True)
> +        except Exception, exc:
> +            self.log.exception("BH: Batch create tickets failed %s" %
> (exc,))
> +            req.send(str(exc), 'plain/text', 500)
> +        else:
> +            tres = Neighborhood('product', product)('ticket', tid)
> +            href = req.href
> +            req.send(to_json({'product': product, 'id': tid,
> +                              'url': get_resource_url(self.env, tres,
> href)}),
> +                     'application/json')
> +
> +    def _get_ticket_module(self):
> +        ptm = None
> +        if ProductTicketModule is not None:
> +            ptm = self.env[ProductTicketModule]
> +        tm = self.env[TicketModule]
> +        if not (tm is None) ^ (ptm is None):
> +            raise TracError('Unable to load TicketModule (disabled)?')
> +        if tm is None:
> +            tm = ptm
> +        return tm
> +
> +    #Template Stream Filter methods
> +    def filter_stream(self, req, method, filename, stream, data):
> +        #headers =
> {'summary':'Summary','description':'Description','product':'Product','status':'Status','priority':'Priority','type':'Type','owner':'Owner','cc':'Cc','keywords':'Keywords','milestone':'Milestone'}
> +        headers =
> {'summary':'Summary','description':'Description','product':'Product','status':'Status'}
> +        xpath = '//div[@id="content"]'
> +        div = tag.div(class_="span12", id="batch_create_empty_table")
> +        text = tag.text("Batch Create Tickets")
> +        h1 = tag.h1(text)
> +        div.append(h1)
> +        form = tag.form(id="qct-form", name="bct", method="post",
> action=req.href()+"/bct")
> +        table = tag.table(class_="listing tickets table table-bordered
> table-condensed query", style="border-radius: 0px 0px 4px 4px")
> +        tr = tag.tr(class_="trac-columns")
> +        for header in sorted(headers):
> +            font = tag.font(color="#1975D1")
> +            text = tag.text(headers[header])
> +            font.append(text)
> +            th = tag.th(font)
> +            tr.append(th)
> +        table.append(tr)
> +        tbody = tag.tbody()
> +        for num in range(0,5):
> +            tr_rows = tag.tr()
> +            for header in sorted(headers):
> +                if header == "summary":
> +                    td_row = tag.td()
> +                    input_summary = tag.input(type="text", id =
> "field-summary"+str(num), class_="input-block-level",
> name="field_summary"+str(num))
> +                    td_row.append(input_summary)
> +                    tr_rows.append(td_row)
> +                elif header == "description":
> +                    td_row = tag.td()
> +                    input_description = tag.textarea(id =
> "field-description"+str(num), name="field_description"+str(num),
> class_="input-block-level", rows="1", cols="28")
> +                    td_row.append(input_description)
> +                    tr_rows.append(td_row)
> +                elif header == "status":
> +                    td_row = tag.td()
> +                    input_status = tag.select(id =
> "field-status"+str(num), name="field_status"+str(num))
> +                    option = tag.option(value="accepted")
> +                    text = tag.text("accepted")
> +                    option.append(text)
> +                    input_status.append(option)
> +                    option = tag.option(value="assigned")
> +                    text = tag.text("assigned")
> +                    option.append(text)
> +                    input_status.append(option)
> +                    option = tag.option(value="closed")
> +                    text = tag.text("closed")
> +                    option.append(text)
> +                    input_status.append(option)
> +                    option = tag.option(value="new", selected="selected")
> +                    text = tag.text("new")
> +                    option.append(text)
> +                    input_status.append(option)
> +                    option = tag.option(value="reopened")
> +                    text = tag.text("reopened")
> +                    option.append(text)
> +                    input_status.append(option)
> +                    td_row.append(input_status)
> +                    tr_rows.append(td_row)
> +                elif header == "priority":
> +                    td_row = tag.td()
> +                    input_priority = tag.select(id =
> "field-priority"+str(num), name="field_priority"+str(num))
> +                    option = tag.option(value="blocker")
> +                    text = tag.text("blocker")
> +                    option.append(text)
> +                    input_priority.append(option)
> +                    option = tag.option(value="critical")
> +                    text = tag.text("critical")
> +                    option.append(text)
> +                    input_priority.append(option)
> +                    option = tag.option(value="major")
> +                    text = tag.text("major")
> +                    option.append(text)
> +                    input_priority.append(option)
> +                    option = tag.option(value="minor",
> selected="selected")
> +                    text = tag.text("minor")
> +                    option.append(text)
> +                    input_priority.append(option)
> +                    option = tag.option(value="trivial")
> +                    text = tag.text("trivial")
> +                    option.append(text)
> +                    input_priority.append(option)
> +                    td_row.append(input_priority)
> +                    tr_rows.append(td_row)
> +                elif header=="type":
> +                    td_row = tag.td()
> +                    input_type = tag.select(id = "field-type"+str(num),
> name="field_type"+str(num))
> +                    option = tag.option(value="defect")
> +                    text = tag.text("defect")
> +                    option.append(text)
> +                    input_type.append(option)
> +                    option = tag.option(value="enhancement")
> +                    text = tag.text("enhancement")
> +                    option.append(text)
> +                    input_type.append(option)
> +                    option = tag.option(value="task", selected="selected")
> +                    text = tag.text("task")
> +                    option.append(text)
> +                    input_type.append(option)
> +                    td_row.append(input_type)
> +                    tr_rows.append(td_row)
> +                elif header == "product":
> +                    td_row = tag.td()
> +                    input_product = tag.select(id =
> "field-product"+str(num), name="field_product"+str(num))
> +                    option = tag.option(value="")
> +                    text = tag.text("Choose...")
> +                    option.append(text)
> +                    input_product.append(option)
> +                    option = tag.option(value="@")
> +                    text = tag.text("Default")
> +                    option.append(text)
> +                    input_product.append(option)
> +                    td_row.append(input_product)
> +                    tr_rows.append(td_row)
> +                elif header == "owner":
> +                    td_row = tag.td()
> +                    input_owner = tag.input(type="text", id =
> "field-owner"+str(num), class_="input-block-level",
> name="field_owner"+str(num))
> +                    td_row.append(input_owner)
> +                    tr_rows.append(td_row)
> +                elif header == "cc":
> +                    td_row = tag.td()
> +                    input_cc = tag.input(type="text", id =
> "field-cc"+str(num), class_="input-block-level", name="field_cc"+str(num))
> +                    td_row.append(input_cc)
> +                    tr_rows.append(td_row)
> +                elif header == "milestone":
> +                    td_row = tag.td()
> +                    input_cc = tag.input(type="text", id =
> "field-milestone"+str(num), class_="input-block-level",
> name="field_milestone"+str(num))
> +                    td_row.append(input_cc)
> +                    tr_rows.append(td_row)
> +                elif header == "keywords":
> +                    td_row = tag.td()
> +                    input_cc = tag.input(type="text", id =
> "field-keywords"+str(num), class_="input-block-level",
> name="field_keywords"+str(num))
> +                    td_row.append(input_cc)
> +                    tr_rows.append(td_row)
> +            tbody.append(tr_rows)
> +        table.append(tbody)
> +        form.append(table)
> +        div_button = tag.div(class_="btn-group pull-right")
> +        input_button = tag.input(type="submit", class_="btn pull-right",
> name="save", value="save")
> +        div_button.append(input_button)
> +        form.append(div_button)
> +        div.append(form)
> +        div.append("\n")
> +        stream |= Transformer(xpath).append(div)
> +        return stream
> +
>      # Public API
>      def batch_create(self, req, attributes={}, notify=False):
>          """ Create batch of tickets, returning created tickets.
> -
>          """
>          num_of_tkts = attributes.__len__()/4
>          for i in range(0,num_of_tkts):
> @@ -722,6 +988,3 @@ class QuickCreateTicketDialog(Component)
>          created_tickets = t._get_tickets_by_id(prev_max+1)
>          return t['product'], t.id, created_tickets
>
> -
> -from pkg_resources import get_distribution
> -application_version = get_distribution('BloodhoundTheme').version
>
> Modified:
> bloodhound/branches/bep_0011_batch_create_tickets/trac/trac/ticket/model.py
> URL:
> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/trac/trac/ticket/model.py?rev=1603720&r1=1603719&r2=1603720&view=diff
>
> ==============================================================================
> ---
> bloodhound/branches/bep_0011_batch_create_tickets/trac/trac/ticket/model.py
> (original)
> +++
> bloodhound/branches/bep_0011_batch_create_tickets/trac/trac/ticket/model.py
> Thu Jun 19 06:05:23 2014
> @@ -109,6 +109,20 @@ class Ticket(object):
>              if default:
>                  self.values.setdefault(field['name'], default)
>
> +    def _get_max_ticket_id(self):
> +        return self.env.db_query("SELECT MAX(id) FROM ticket")
> +
> +    def _get_tickets_by_id(self, tkt_id):
> +        #this method returns standard ticket fields of all the tickets
> which have a ticket id over the parameter id value
> +        row = None
> +        if self.id>=tkt_id:
> +            # Fetch the standard ticket fields
> +            return self.env.db_query("SELECT %s FROM ticket WHERE
> id>=%%s" %
> +                                        ','.join(self.std_fields),
> (tkt_id,))
> +        else:
> +            raise ResourceNotFound(_("Ticket %(id)s does not exist.",
> +                                    id=self.id), _("Invalid ticket
> number"))
> +
>      def _fetch_ticket(self, tkt_id):
>          row = None
>          if self.id_is_valid(tkt_id):
>
>
>


-- 
Dammina Sahabandu.
Committer for ASF (Apache Bloodhound)
Undergraduate Department of Computer Science and Engineering
University of Moratuwa
Sri Lanka.