Beispiel #1
0
 def test_compound_types(self):
     self.assertEqual('[1,2,[true,false]]',
                      presentation.to_json([1, 2, [True, False]]))
     self.assertEqual(r'{"one":1,"other":[null,0],'
                      r'"three":[3,"\u0026\u003c\u003e"],'
                      r'"two":2}',
                      presentation.to_json({"one": 1, "two": 2,
                                            "other": [None, 0],
                                            "three": [3, "&<>"]}))
Beispiel #2
0
 def test_compound_types(self):
     self.assertEqual('[1,2,[true,false]]',
                      presentation.to_json([1, 2, [True, False]]))
     self.assertEqual(r'{"one":1,"other":[null,0],'
                      r'''"three":[3,"\u0026\u003c\u003e'"],'''
                      r'"two":2,"\u2028\n":"\u2029\r"}',
                      presentation.to_json({"one": 1, "two": 2,
                                            "other": [None, 0],
                                            "three": [3, "&<>'"],
                                            u"\u2028\x0a": u"\u2029\x0d"}))
Beispiel #3
0
 def test_compound_types(self):
     self.assertEqual('[1,2,[true,false]]',
                      presentation.to_json([1, 2, [True, False]]))
     self.assertEqual(r'{"one":1,"other":[null,0],'
                      r'''"three":[3,"\u0026\u003c\u003e'"],'''
                      r'"two":2,"\u2028\n":"\u2029\r"}',
                      presentation.to_json({"one": 1, "two": 2,
                                            "other": [None, 0],
                                            "three": [3, "&<>'"],
                                            u"\u2028\x0a": u"\u2029\x0d"}))
Beispiel #4
0
 def test_simple_types(self):
     self.assertEqual('42', presentation.to_json(42))
     self.assertEqual('123.456', presentation.to_json(123.456))
     self.assertEqual('true', presentation.to_json(True))
     self.assertEqual('false', presentation.to_json(False))
     self.assertEqual('null', presentation.to_json(None))
     self.assertEqual('"String"', presentation.to_json('String'))
     self.assertEqual(r'"a \" quote"', presentation.to_json('a " quote'))
     self.assertEqual('''"a ' single quote"''',
                      presentation.to_json("a ' single quote"))
     self.assertEqual(r'"\u003cb\u003e\u0026\u003c/b\u003e"',
                      presentation.to_json('<b>&</b>'))
     self.assertEqual(r'"\n\r\u2028\u2029"',
                      presentation.to_json(u'\x0a\x0d\u2028\u2029'))
Beispiel #5
0
 def test_simple_types(self):
     self.assertEqual('42', presentation.to_json(42))
     self.assertEqual('123.456', presentation.to_json(123.456))
     self.assertEqual('true', presentation.to_json(True))
     self.assertEqual('false', presentation.to_json(False))
     self.assertEqual('null', presentation.to_json(None))
     self.assertEqual('"String"', presentation.to_json('String'))
     self.assertEqual(r'"a \" quote"', presentation.to_json('a " quote'))
     self.assertEqual('''"a ' single quote"''',
                      presentation.to_json("a ' single quote"))
     self.assertEqual(r'"\u003cb\u003e\u0026\u003c/b\u003e"',
                      presentation.to_json('<b>&</b>'))
     self.assertEqual(r'"\n\r\u2028\u2029"',
                      presentation.to_json(u'\x0a\x0d\u2028\u2029'))
    def process_request(self, req):

        q = req.args.get('q')
        dirname, prefix = posixpath.split(q)
        prefix = prefix.lower()

        def kind_order(entry):
            return (not entry['id'], embedded_numbers(entry['id']))

        bm_entries = {'text': _('Favorites'),
                      'children': [],
                      }
        result = []

        # if no query then we only need to return the favorites.
        if not q:
            bm_entries['children'].extend({'id': bm.path,
                                           'text': bm.path,
                                           'is_favorite': True
                                           } for bm in VCSFavorite.select_all(self.env)
                                          )
            bm_entries['children'] = sorted(bm_entries['children'], key=kind_order)
            result.append(bm_entries)
            json = to_json(result)
            req.send(json, 'text/json')
            return

        repo_entries = self._get_vcs_folders(req, q, dirname, prefix)

        bm_entries['children'].extend({'id': bm.path,
                                       'text': bm.path,
                                       'is_favorite': True
                                       } for bm in VCSFavorite.select_all_path_begins_with(self.env, q)
                                      )

        for b_entry in bm_entries['children']:
            for r_entry in repo_entries['children']:
                if r_entry['text'] == b_entry['text'] or r_entry['text'] == (b_entry['text'] + '/'):
                    r_entry['is_favorite'] = True
                    break

        bm_entries['children'] = sorted(bm_entries['children'], key=kind_order)
        repo_entries['children'] = sorted(repo_entries['children'], key=kind_order)
        if bm_entries['children']:
            result.append(bm_entries)
        if repo_entries['children']:
            result.append(repo_entries)
        json = to_json(result)
        req.send(json, 'text/json')
Beispiel #7
0
    def write_js(fileobj, catalog, domain, locale):
        from trac.util.presentation import to_json

        data = {"domain": domain, "locale": locale}

        messages = {}
        for msgid, msgstr in catalog.iteritems():
            if isinstance(msgid, (list, tuple)):
                messages.setdefault(msgid[0], {})
                messages[msgid[0]][msgid[1]] = msgstr
            elif msgid:
                messages[msgid] = msgstr
            else:
                for line in msgstr.splitlines():
                    line = line.strip()
                    if not line:
                        continue
                    if ":" not in line:
                        continue
                    name, val = line.split(":", 1)
                    name = name.strip().lower()
                    if name == "plural-forms":
                        data["plural_expr"] = pluralexpr(val)
                        break
        data["messages"] = messages

        fileobj.write("// Generated messages javascript file " "from compiled MO file\n")
        fileobj.write("babel.Translations.load(")
        fileobj.write(to_json(data).encode("utf-8"))
        fileobj.write(").install();\n")
Beispiel #8
0
Datei: dist.py Projekt: t2y/trac
    def write_js(fileobj, catalog, domain, locale):
        from trac.util.presentation import to_json
        data = {'domain': domain, 'locale': locale}

        messages = {}
        for msgid, msgstr in catalog.iteritems():
            if isinstance(msgid, (list, tuple)):
                messages.setdefault(msgid[0], {})
                messages[msgid[0]][msgid[1]] = msgstr
            elif msgid:
                messages[msgid] = msgstr
            else:
                for line in msgstr.splitlines():
                    line = line.strip()
                    if not line:
                        continue
                    if ':' not in line:
                        continue
                    name, val = line.split(':', 1)
                    name = name.strip().lower()
                    if name == 'plural-forms':
                        data['plural_expr'] = pluralexpr(val)
                        break
        data['messages'] = messages

        fileobj.write('// Generated messages javascript file '
                      'from compiled MO file\n')
        fileobj.write('babel.Translations.load(')
        fileobj.write(to_json(data).encode('utf-8'))
        fileobj.write(').install();\n')
Beispiel #9
0
    def write_js(fileobj, catalog, domain, locale):
        from trac.util.presentation import to_json
        data = {'domain': domain, 'locale': locale}

        messages = {}
        for msgid, msgstr in catalog.iteritems():
            if isinstance(msgid, (list, tuple)):
                messages.setdefault(msgid[0], {})
                messages[msgid[0]][msgid[1]] = msgstr
            elif msgid:
                messages[msgid] = msgstr
            else:
                for line in msgstr.splitlines():
                    line = line.strip()
                    if not line:
                        continue
                    if ':' not in line:
                        continue
                    name, val = line.split(':', 1)
                    name = name.strip().lower()
                    if name == 'plural-forms':
                        data['plural_expr'] = pluralexpr(val)
                        break
        data['messages'] = messages

        fileobj.write('// Generated messages javascript file '
                      'from compiled MO file\n')
        fileobj.write('babel.Translations.load(')
        fileobj.write(to_json(data).encode('utf-8'))
        fileobj.write(').install();\n')
Beispiel #10
0
    def embed_player(self, formatter, url, query, style):
        query_dict = xform_query(query)
        set_default_parameters(
            query_dict,
            _EMBED_FLOWPLAYER_DEFAULT_PARAMETERS
        )

        player_id = self._generate_player_id()
        swf = pathjoin(formatter.href.chrome(), EMBED_PATH_FLOWPLAYER['swf'])
        style.pop('width')  # use adaptiveRatio for player-size
        style.pop('height')  # use adaptiveRatio for player-size
        attrs = {
            'id': player_id,
            'data-swf': swf,
            'style': xform_style(style),
        }
        return tag.div(
            tag.video([
                tag.source(type=mimetypes.guess_type(url)[0], src=url),
                tag.script("""
                    $(function() {
                        $('#%s').flowplayer(%s);
                    });
                """ % (player_id, to_json(query_dict))
                ),
            ]),
            **attrs
        )
Beispiel #11
0
 def process_request(self, req):
     product = req.args.get('product')
     fields_to_update = req.args.get('fields_to_update[]');
     env = ProductEnvironment(self.env.parent, req.args.get('product'))
     ticket_fields = TicketSystem(env).get_ticket_fields()
     data = dict([f['name'], f['options']]  for f in ticket_fields
         if f['type'] == 'select' and f['name'] in fields_to_update)
     req.send(to_json(data), 'application/json')
 def process_request(self, req):
     if req.path_info.startswith(self.ownurl):
         req.perm.require('TICKET_VIEW')
         users = self._session_query(req.args['q'], int(req.args.get('limit', 10)))
         body = to_json(list(users)).encode('utf8')
         req.send_response(200)
         req.send_header('Content-Type', "application/json")
         req.send_header('Content-Length', len(body))
         req.end_headers()
         req.write(body)
Beispiel #13
0
 def to_json(value):
     """Encode `value` to JSON."""
     if isinstance(value, basestring):
         return '"%s"' % javascript_quote(value)
     elif value is None:
         return 'null'
     elif value is False:
         return 'false'
     elif value is True:
         return 'true'
     elif isinstance(value, (int, long)):
         return str(value)
     elif isinstance(value, float):
         return repr(value)
     elif isinstance(value, (list, tuple)):
         return '[%s]' % ','.join(to_json(each) for each in value)
     elif isinstance(value, dict):
         return '{%s}' % ','.join('%s:%s' % (to_json(k), to_json(v))
                                  for k, v in sorted(value.iteritems()))
     else:
         raise TypeError('Cannot encode type %s' % value.__class__.__name__)
Beispiel #14
0
 def to_json(value):
     """Encode `value` to JSON."""
     if isinstance(value, basestring):
         return '"%s"' % javascript_quote(value)
     elif value is None:
         return 'null'
     elif value is False:
         return 'false'
     elif value is True:
         return 'true'
     elif isinstance(value, (int, long)):
         return str(value)
     elif isinstance(value, float):
         return repr(value)
     elif isinstance(value, (list, tuple)):
         return '[%s]' % ','.join(to_json(each) for each in value)
     elif isinstance(value, dict):
         return '{%s}' % ','.join('%s:%s' % (to_json(k), to_json(v))
                                  for k, v in sorted(value.iteritems()))
     else:
         raise TypeError('Cannot encode type %s' %
                         value.__class__.__name__)
    def process_request(self, req):
        """
        If the request is AJAX, inserts a new row into the record table for 
        the authenticated user to show they have seen a particular 
        notification.

        If the request is a normal GET, try and show the appropriate full 
        screen project message.
        """

        if req.path_info.startswith('/projectmessage'):
            try:
                name = req.path_info.split('/projectmessage/')[1]
            except IndexError:
                name = None
                self.log.debug("No project messages to show at "
                                "/projectmessage")

            if name:
                try:
                    msg = ProjectMessage(self.env, name)
                except ResourceNotFound:
                    self.log.debug("No project messages found")
                else:
                    add_script(req, 'projectmessage/js/project_message.js')
                    data = {
                        'name': msg['name'],
                        'message': msg['message'],
                        'button': msg['button'],
                    }
                    return 'project_message.html', data, None
            data = {'message': 'No project messages to show.'}
            return 'project_message.html', data, None

        elif (req.method == 'POST' and
                req.path_info.startswith('/ajax/projectmessage')):
            if req.args.get('name'):
                new_record = ProjectMessageRecord(self.env)
                new_record.populate(req)
                try:
                    new_record.insert()
                except:
                    self.log.info("Unable to create record that %s agreed "
                                  " to %s", new_record['agreed_by'], 
                                  new_record['message_name'])
                finally:
                    self.log.debug("Created a new record to show %s agreed "
                                   "to %s", new_record['agreed_by'],
                                   new_record['message_name'])
                data = {'success': True}
                req.send(to_json(data), 'text/json')
    def _set_default_query(self, req):
        """Processes a POST request to save a user based query on the task 
        board. After validating the various values passed in req.args, the 
        session_attribute table is updated and a JSON repsonse returned."""

        data = {}
        status_code = 422
        default_milestone = req.args.get('milestone')
        default_group = req.args.get('group')
        default_fields = req.args.get('col')
        default_view = req.args.get('view')

        if all([default_milestone, default_group, default_fields, default_view]):

            try:
                Milestone(self.env, default_milestone)
            except ResourceNotFound:
                data['invalid_milestone'] = default_milestone

            display_fields = default_fields.split(',')
            for f in chain([default_group], display_fields):
                if f not in self.valid_display_field_names:
                    data['invalid_field'] = f
                    break

            if default_view not in ['condensed', 'expanded']:
                data['invalid_view'] = default_view

            if not data:
                req.session.update({
                    'taskboard_user_default_milestone': default_milestone,
                    'taskboard_user_default_group': default_group,
                    'taskboard_user_default_fields': json.dumps(display_fields),
                    'taskboard_user_default_view': default_view
                })
                req.session.save()
                status_code = 200

        req.send(to_json(data), 'text/json', status=status_code)
    def process_request(self, req):
        """
        Send a JSON response containing workload data to a XMLHttpRequest. Any 
        other type of request raise a TracError.
        """

        if not req.get_header('X-Requested-With') == 'XMLHttpRequest':
            raise TracError("We only accept XMLHttpRequests to this URL")

        milestone = self._get_milestone(req.args['id'])

        if milestone:
            closed_count = self._limit_user_data(self._get_closed_ticket_count(milestone.name))
            logged_count = self._limit_user_data(self._get_hours_logged(milestone.name))
            data = {
                'closed_tickets': self._limit_user_data(closed_count),
                'closed_tickets_other': self._other_user_query_string(closed_count),
                'logged_hours': self._limit_user_data(logged_count),
                'logged_hours_other': self._other_user_query_string(logged_count),
            }

            if milestone.completed:
                data['milestone_completed'] =  True
            else:
                ticket_count = self._limit_user_data(self._get_open_ticket_count(milestone.name))
                hour_count = self._limit_user_data(self._get_remaining_hours(milestone.name))
                data.update({
                    'milestone_completed': False,
                    'remaining_tickets': self._limit_user_data(ticket_count),
                    'remaing_tickets_other': self._other_user_query_string(ticket_count),
                    'remaining_hours': self._limit_user_data(hour_count),
                    'remaining_hours_other': self._other_user_query_string(hour_count),
                })
        else:
            data = {}

        req.send(to_json(data, cls=DecimalEncoder), 'text/json')
    def process_request(self, req):
        """
        Sets a session attribute to show the user has seen the tortoise svn 
        repo browser dialog.

        This request will only ever be via a POST with Ajax. As a result, 
        if the request is a GET or does not have a XMLHttpRequest header 
        we redirect the user back to the browser page.

        Once the new session attribute is set, we send a JSON respsone. We 
        stop showing the dialog box when this attribute is set. 
        """

        if (req.method == "POST" and
          req.get_header('X-Requested-With') == 'XMLHttpRequest' and
          req.args.get('tortoise-svn-message')):
            req.session['tortoise_svn_message'] = True
            self.log.info("Set tortoise_svn_message session attribute "
                              "as True for %s", req.authname)
            req.session.save()
            req.send(to_json({"success":True}), 'text/json')
        else:
            # if you try to access this page via GET we redirect
            req.redirect(req.href.browser())
    def _enable_autocomplete_for_page(self, req, method, filename, stream, data, inputs):
        add_stylesheet(req, 'autocomplete/css/autocomplete.css')
        add_script(req, 'autocomplete/js/jquery.tracautocomplete.js')

        username_completers = list(self._username_completers(req))
        add_script_data(req, {'username_completers': username_completers})
                
        # we could put this into some other URL which the browser could cache?
        #show users from all groups, shown or not, on the members page
        add_script_data(req, {'project_users': self._project_users})

        controls = (self._split_input(input_) for input_ in inputs)
        js = ''.join('$("%s").makeAutocompleteSearch("%s", %s);\n'
                     % (selector, method_ or 'select',
                        options if isinstance(options, basestring)
                        else to_json(options))
                     for selector, method_, options in controls)
                
        stream = stream | Transformer('//head').append(tag.script("""
        jQuery(document).ready(function($) {
        %s
        });
        """ % js,type="text/javascript"))
        return stream
 def to_json(data):
     from trac.util.presentation import to_json
     text = to_json(data)
     if isinstance(text, unicode):
         text = text.encode('utf-8')
     return text
Beispiel #21
0
 def _send_json(self, req, data):
     req.send(to_json(data), 'application/json')
Beispiel #22
0
 def test_simple_types(self):
     self.assertEqual('42', presentation.to_json(42))
     self.assertEqual('123.456', presentation.to_json(123.456))
     self.assertEqual('true', presentation.to_json(True))
     self.assertEqual('false', presentation.to_json(False))
     self.assertEqual('null', presentation.to_json(None))
     self.assertEqual('"String"', presentation.to_json('String'))
     self.assertEqual('1551895815012345',
                      presentation.to_json(datetime.datetime(
                          2019, 3, 6, 18, 10, 15, 12345, datefmt.utc)))
     self.assertEqual('1551895815012345',
                      presentation.to_json(datetime.datetime(
                          2019, 3, 6, 18, 10, 15, 12345)))
     self.assertEqual(r'"a \" quote"', presentation.to_json('a " quote'))
     self.assertEqual('''"a ' single quote"''',
                      presentation.to_json("a ' single quote"))
     self.assertEqual(r'"\u003cb\u003e\u0026\u003c/b\u003e"',
                      presentation.to_json('<b>&</b>'))
     self.assertEqual(r'"\n\r\u2028\u2029"',
                      presentation.to_json(u'\x0a\x0d\u2028\u2029'))
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        db = self.env.get_db_cnx()
        # prepare options
        options, query_args = parse_options(db, content, copy.copy(DEFAULT_OPTIONS))

        query_args[self.estimation_field + "!"] = None
        query_args['col'] = '|'.join([self.totalhours_field, 'owner'])
        tickets = execute_query(self.env, req, query_args)

        sum = 0.0
        estimations = {}
        for ticket in tickets:
            if ticket['status'] in self.closed_states:
                continue
            try:
                estimation = float(ticket[self.estimation_field]) - float(ticket[self.totalhours_field])
                owner = ticket['owner']
                sum += estimation
                if estimations.has_key(owner):
                    estimations[owner] += estimation
                else:
                    estimations[owner] = estimation
            except:
                pass

        data = []
        data.append(['Owner', 'Workload'])

        for owner, estimation in estimations.iteritems():
            estimation = max(0, estimation)
            label = "%s %g%s" % (obfuscate_email_address(owner),
                            round(estimation, 2),
                            self.estimation_suffix)
            data.append([label, float(estimation)])

        # Title
        title = 'Workload'

        # calculate remaining work time
        if options.get('today') and options.get('enddate'):
            currentdate = options['today']
            day = timedelta(days=1)
            days_remaining = 0
            while currentdate <= options['enddate']:
                if currentdate.weekday() < 5:
                    days_remaining += 1
                currentdate += day
            title += ' %g%s (~%s workdays left)' % (round(sum, 2),
                                    self.estimation_suffix, days_remaining)

        element_id = 'chart-%d' % random.randint(0, 0xffffffff)
        args = {
            'containerId': element_id,
            'chartType': 'PieChart',
            'options': {
                'width': int(options['width']),
                'height': int(options['height']),
                'title': title,
                'legend': { 'position': 'labeled' },
                'pieSliceText': 'none',
                'tooltip': 'percentage',
            },
        }
        script = "EstimationCharts.push(function() {\n"
        script += 'var data=' + to_json(data) + ";\n"
        script += 'var args=' + to_json(args) + ";\n"
        script += 'DrawWorkloadChart(data, args);'
        script += '});'

        return tag.div(tag.div(id=element_id), tag.script(script))
    def process_request(self, req):
        """Collect the data needed for a burndown chart and pass to JavaScript. 
        If the original request was via AJAX we use to_json, otherwise
        we return data via add_script_data.

        Remember that our data reflects how a project looked at the end of a 
        day - so if the ticket_bi_historical table has 20 opens tickets on 
        the 1st December, that were 20 open tickets at the end of that day.
        """

        # Get milestone object and all child milestones
        # we already know it exists, as we checked in the match_request()
        milestone = Milestone(self.env, req.args['id'])
        tree = Milestone.build_tree(self.env)
        all_milestones = [m.name for m in tree.find(milestone.name).traverse()]

        # If anyone request burndownchart/milestone_id not via AJAX
        # and not with a format argument (eg when printing) , we redirect to 
        # milestone/milestonename, as we need to load pre_process_request first
        XMLHttp = req.get_header('X-Requested-With') == 'XMLHttpRequest'
        if not XMLHttp and 'format' not in req.args:
            req.redirect(req.href.milestone(milestone.name))

        # Calculate series of dates used to render the burn down charts
        start = self.get_start_date(req, milestone)
        end = self.get_end_date(milestone)
        day_before_start = start - timedelta(days=1)
        dates = self.dates_inbetween(day_before_start, end)

        # Open a database connection
        self.log.debug('Connecting to the database to retrieve chart data')
        db = self.env.get_read_db()

        # If no metric data is posted, use the project default self.unit_value
        metric = req.args.get('metric', self.unit_value)

        # Remaining Effort (aka burndown) Curve
        remaining_effort_args = [db, all_milestones, day_before_start, end]

        burndown_series = []
        if metric == 'tickets':
            burndown_series = self.tickets_open_between_dates(*remaining_effort_args)
        elif metric == 'hours':
            burndown_series = self.hours_remaining_between_dates(*remaining_effort_args)
        elif metric == 'points':
            burndown_series = self.points_remaining_between_dates(*remaining_effort_args)

        # If we don't have any burndown data send a message and stop
        if not burndown_series:
            data = {'result': False}
            # For ajax request
            if XMLHttp:
                req.send(to_json(data), 'text/json')
            else:
                return 'burndown_print.html', data, None

        # Team Effort Curve
        team_effort = self.team_effort_curve(db, metric, all_milestones,
                                                day_before_start, end,
                                                self.dates_as_strings(dates))

        # Ideal Curve (unit value doesnt matter)
        if self.ideal_value == 'fixed':
            original_estimate = burndown_series[0][1]

        ideal_data = self.ideal_curve(original_estimate, day_before_start, 
                                      self.get_due_date(milestone))

        data = {
            'burndowndata': burndown_series,
            'teameffortdata' : team_effort,
            'idealcurvedata': ideal_data,
            'milestone_name': milestone.name,
            'start_date': str(day_before_start),
            'effort_units': metric,
            'yaxix_label': metric.title(),
            'result' : True,
        }

        # we need some logic to work out the end date on the xAxis
        data['due_date'] =  (self.get_due_date(milestone)).strftime("%Y-%m-%d")

        # Ajax request
        if XMLHttp:
            kwargs = { 'daysback':0,
                       'ticket':'on',
                       'ticket_details': 'on',
                       'ticket_milestone_%s' % Milestone._hash_name(milestone.name): 'on'
                     }
            data.update({
              'timeline_url': req.href.timeline(kwargs),
              'print_burndown': False,
              'render_burndown': True,
            })

            req.send(to_json(data), 'text/json')

        # Normal request (eg the print friendly page)
        else:
            if req.args.get('format') == 'print':
                # Load the burn down JS file and jqPlot library 
                add_script(req, 'burndown/js/burndown.js')
                self._add_static_files(req)

                result = {'data': data,
                          'print_burndown': True,
                          'render_burndown': True,
                          'result': True,
                         }

                add_script_data(req, result)
                return 'burndown_print.html', result, None
        if not failures:
            try:
                files = self.send_as_email(req, sender, recipients, subject, message, mode, *to_send)
            except Exception, e:
                files = []
                failures.append(str(e))
        else:
            files = []
        response = dict(files=files, recipients=[x[1] for x in recipients],
                        failures=failures)
        if failures != []:
            msg = ", ".join(failures)
            add_warning(req, msg)
            self.log.error('Failures in source sharing: %s', msg)
        if 'XMLHttpRequest' == req.get_header('X-Requested-With'):
            req.send(to_json(response), 'text/json')
        else:
            add_notice(req, _("Sent %(files)s to %(recipients)s",
                         files=', '.join(files),
                         recipients=', '.join([x[1] for x in recipients])))
            req.redirect()

    def match_request(self, req):
        return req.path_info == '/share'

    # IPermissionRequestor methods

    def get_permission_actions(self):
        return ['BROWSER_VIEW', 'FILE_VIEW']

    #IAutoCompleteUser
    def process_request(self, req):

        req.perm.assert_permission('TICKET_VIEW')

        # set the default user query
        if req.path_info == '/taskboard/set-default-query' and req.method == 'POST':
            self._set_default_query(req)

        # these headers are only needed when we update tickets via ajax
        req.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
        req.send_header("Pragma", "no-cache")
        req.send_header("Expires", 0)

        xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest'

        group_by = req.args.get("group", "status")

        user_saved_query = False

        milestones = Milestone.select_names_select2(self.env, include_complete=False)

        # Try to find a user selected milestone in request - if not found 
        # check session_attribute for a user saved default, and if that is also
        # not found and fall back on the most upcoming milestone by due date
        milestone = req.args.get("milestone")
        milestone_not_found = False
        if milestone:
            try:
                Milestone(self.env, milestone)
            except ResourceNotFound:
                milestone_not_found = True
                milestone = None

        if not milestone:
            # try and find a user saved default
            default_milestone = req.session.get('taskboard_user_default_milestone')
            if default_milestone:
                milestone = default_milestone
                group_by = req.session.get('taskboard_user_default_group')
                user_saved_query = True

            # fall back to most imminent milestone by due date
            elif len(milestones["results"]):
                milestone = milestones["results"][0]["text"]

        # Ajax post
        if req.args.get("ticket") and xhr:
            result = self.save_change(req, milestone)
            req.send(to_json(result), 'text/json')
        else:
            data = {}
            constr = {}

            if milestone:
                constr['milestone'] = [milestone]

            # Ajax update: tickets changed between a period
            if xhr:
                from_iso = req.args.get("from", "")
                to_iso = req.args.get("to", "")
                if from_iso and to_iso:
                    constr['changetime'] = [from_iso + ".." + to_iso]

            # Get all tickets by milestone and specify ticket fields to retrieve
            cols = self._get_display_fields(req, user_saved_query)
            tickets = self._get_permitted_tickets(req, constraints=constr, 
                                                  columns=cols)
            sorted_cols = sorted([f for f in self.valid_display_fields
                    if f['name'] not in ('summary', 'type')],
                    key=lambda f: f.get('label'))

            if tickets:
                s_data = self.get_ticket_data(req, milestone, group_by, tickets)
                s_data['total_tickets'] = len(tickets)
                s_data['display_fields'] = cols
                data['cur_group'] = s_data['groupName']
            else:
                s_data = {}
                data['cur_group'] = group_by

            if xhr:
                if constr.get("changetime"):
                    s_data['otherChanges'] = \
                        self.all_other_changes(req, tickets, constr['changetime'])

                req.send(to_json(s_data), 'text/json')
            else:
                s_data.update({
                    'formToken': req.form_token,
                    'milestones': milestones,
                    'milestone': milestone,
                    'group': group_by,
                    'default_columns': self.default_display_fields
                })
                data.update({
                    'milestone_not_found': milestone_not_found,
                    'current_milestone': milestone,
                    'group_by_fields': self.valid_grouping_fields,
                    'fields': dict((f['name'], f) for f in self.valid_display_fields),
                    'all_columns': [f['name'] for f in sorted_cols],
                    'col': cols,
                    'condensed': self._show_condensed_view(req, user_saved_query)
                })

                add_script(req, 'agiletools/js/update_model.js')
                add_script(req, 'agiletools/js/taskboard.js')
                add_script(req, 'common/js/query.js')
                add_script_data(req, s_data)

                add_stylesheet(req, 'agiletools/css/taskboard.css')
                add_stylesheet(req, 'common/css/ticket.css')
                add_ctxtnav(req, tag.a(tag.i(class_='fa fa-bookmark'),
                                       _(" Set as default"),
                                       id_='set-default-query',
                                       title=_("Make this your default taskboard")))
                return "taskboard.html", data, None
 def get_templates(self):
     return {"ticket.html": [('#field-keywords', 'text', '{source: %s}' % to_json(
                     self._current_keywords).encode('utf8'))]}
Beispiel #28
0
    def expand_macro(self, formatter, name, content, args=None):
        # Utility methods
        def lte_ie8(req):
            user_agent = formatter.req.get_header('user-agent')
            msie = user_agent.find('MSIE ')
            return (msie != -1) and user_agent[msie + 5:msie + 6] in ['6', '7', '8']

        def after_AS(string):
            index = string.find(' AS ')
            return index > 0 and string[index + 4:] or string

        def before_AS(string):
            index = string.find(' AS ')
            return index > 0 and string[:index] or string
        # add scripts
        if lte_ie8(formatter.req):
            add_script(formatter.req, "statushistorychart/js/flot/excanvas.js")
        add_script(formatter.req, "statushistorychart/js/flot/jquery.flot.js")
        add_script(formatter.req, "statushistorychart/js/flot/jquery.flot.time.js")
        add_script(formatter.req, "statushistorychart/js/enabler.js")
        # from macro parameters
        query = None
        query_href = None
        status_list = ['new', 'assigned', 'accepted', 'closed']  # default
        if(content):
            # replace parameters
            for match in reversed([match for match in re_param.finditer(content)]):
                param_name = match.group(0)
                if param_name == '$USER':
                    authname = formatter.req.authname
                    if authname == 'anonymous':
                        authname = 'anonymous||somebody'
                    content = content.replace(param_name, authname)
                else:
                    param_value = formatter.req.args.get(param_name[1:])
                    if param_value:
                        content = content.replace(param_name, param_value)
            # execute query
            query = Query.from_string(formatter.env, content)
        field = query and query.id or 'status'  # stopgap implementation; I use 'report' for y-axis parameter
        field = filter(lambda x: x['name'] == field, TicketSystem(self.env).fields)
        if len(field) <= 0:
            return tag.div(tag.strong('Error: Macro %s failed' % name),
                       tag.pre("%s is not field name" % query.id), class_="system-message")
        field = field[0]
        custom = 'custom' in field and field['custom'] or None
        status_list = query and query.format and query.format.split('/') or \
                      'options' in field and copy.copy(field['options']) or status_list
        if field['name'] == 'status' and not (query and query.format):
            def isprime(item):
                primaries = ['new', 'assigned', 'accepted', 'closed']
                return (item in primaries and [primaries.index(item)] or [len(primaries)])[0]
            status_list.sort(key=isprime)
        if '*' not in status_list:
            status_list.append('*')
        default_status = status_list.index('*')
        # execute query for ids of ticket
        if(query and len(query.constraint_cols) > 0):
            result = query.execute() or [{'id':-1}]  # Sentinel for no result
            cond = "ticket.id in (%s)" % ', '.join([str(t['id']) for t in result])
        elif formatter.resource.realm == 'milestone':
            cond = "ticket.milestone='%s'" % formatter.resource.id
        elif('query_tickets' in formatter.req.session):  # You Feeling Lucky
            query_tickets = formatter.req.session.get('query_tickets', '')
            query_href = formatter.req.session.get('query_href', '')
            tickets = len(query_tickets) and query_tickets.split(' ') or ['-1']  # Sentinel for no result
            cond = "ticket.id in (%s)" % ', '.join(tickets)
        else:
            raise TracError("%sMacro: Empty. There are no content and no context." % name)
        # execute query for value changes of each ticket
        join_clause_dummy = ''
        join_clause = "JOIN ticket_custom ON ticket.id = ticket_custom.ticket and ticket_custom.name = '%s'"
        cursor = formatter.env.get_read_db().cursor()
        cursor.execute("""
                SELECT id, time, null, %s
                    FROM ticket
                    %s
                    WHERE %s
                UNION
                SELECT id, ticket_change.time, oldvalue, newvalue
                    FROM ticket
                    JOIN ticket_change ON ticket.id = ticket_change.ticket
                    WHERE %s AND field='%s'
                ORDER BY id, time
                """ % (custom and "'\uFEFF'" or field['name'],  # ZERO WIDTH NO-BREAK SPACE; uses for mark of invalid data
                       custom and (join_clause % field['name']) or join_clause_dummy,
                       cond, cond, field['name']))
        changes = [row for row in cursor.fetchall()]
        # transform (ticket, time, status)* ==> (ticket <>- status)*
        tid = 0  # position of ticket id
        tickets = {}
        for change in changes:
            ticket = tickets.get(change[tid])  # slot is exist, or
            if ticket is None:
                ticket = tickets[change[tid]] = []  # create new slot and use it
            ticket.append(list(change))
        # generate status_list splitted, {a, b+c, d} => {a:0, b+c:1, b:1, c:1, d:2}
        status_list_splitted = {}
        for index, status in enumerate(map(before_AS, status_list)):
            status_list_splitted[status] = index
            if status.find('+') >= 0:
                for each in status.split('+'):
                    status_list_splitted[each] = index
#        groupstats = self.compmgr[DefaultTicketGroupStatsProvider]
#        ticket_groups = groupstats._get_ticket_groups()
#        for group in ticket_groups:
#            pass
        for tid in tickets:
            if len(tickets[tid]) > 1:
                tickets[tid][0][3] = tickets[tid][1][2]  # override last value with initial value
        # generate data
        data = []
        # points
        too_many_tickets = len(tickets) > 200
        for no, tid in enumerate(sorted(tickets)):
            if not too_many_tickets or tickets[tid][-1][3] != 'closed':
                void, time, void, state = tickets[tid][-1]  # @UnusedVariable
                index = status_list_splitted.get(state, default_status)
                data.append({'points': {'show': True, 'radius': 8, 'color': no},
                             'label': tid,
                             'data': [[time / 1000, index]]})
        # lines
        for no, tid in enumerate(sorted(tickets)):
            data.append({'color': no, 'label': tid,
                         'data': [[time / 1000, status_list_splitted.get(state, default_status)]
                                  for void, time, void, state in tickets[tid]]})  # @UnusedVariable
        from trac import __version__ as VERSION
        if VERSION[0:1] != '0':
        # render for trac 1.0 or later
            add_script_data(formatter.req, {'statushistorychart_yaxis': map(after_AS, status_list)})
            add_script_data(formatter.req, {'statushistorychart_data': data})
            return tag.a(_("Return to Last Query"), href=query_href) \
                 + tag.div(id="statushistorychart", style="width: 800px; height: 400px;")
        else:  # if trac < 1.0 or earlier
            from trac.util.presentation import to_json
            return tag.script("var statushistorychart_yaxis = %s; var statushistorychart_data = %s" \
                              % (to_json(map(after_AS, status_list)), to_json(data)),
                              type="text/javascript") \
                 + tag.a(_("Return to Last Query"), href=query_href) \
                 + tag.div(id="statushistorychart", style="width: 800px; height: 400px;")
    def process_request(self, req):
        if 'action' in req.args:
            transform_id = self._generate_running_transformation_id()
            parameters = {}
            for k in req.args:
                if k.startswith("parameter:"):
                    parameter_name = k.split(":",2)[1]
                    parameter_value = req.args[k]
                    parameters[parameter_name] = parameter_value
            req.perm.require("BUSINESSINTELLIGENCE_TRANSFORMATION_EXECUTE")
            if req.args['action'] == "execute_async":
                # execute the transformation 
                thread.start_new_thread(self._do_execute_transformation, 
                                        (req.args['transform'],), 
                                        {'transformation_id': transform_id, 'parameters': parameters})
                # send transform_id generated via uuid back to JS via JSON
                # we have to do this after we invoke a new thread as req.send()
                # returns from this function and stops further flow control
                req.send(to_json({'transform_id': transform_id}), 'text/json')
            elif req.args['action'] == "execute_download":
                filename, stat, filestream = self._do_execute_transformation(req.args['transform'], transformation_id=transform_id, store=False, return_bytes_handle=True, parameters=parameters)
                req.send_response(200)
                req.send_header('Content-Type', mimetypes.guess_type(filename)[0] or 'application/octet-stream')
                req.send_header('Content-Length', stat.st_size)
                req.send_header('Content-Disposition', content_disposition('attachment', filename))
                req.end_headers()
                while True:
                    bytes = filestream.read(4096)
                    if not bytes:
                        break
                    req.write(bytes)
                filestream.close()
                raise RequestDone

            elif req.args['action'] == "execute":
                self._do_execute_transformation(req.args['transform'], transformation_id=transform_id, parameters=parameters)
            elif req.args['action'] == 'check_status':
                if 'uuid' not in req.args:
                    raise KeyError
                running_transformations = json.loads(req.args['uuid'])
                req.send(to_json(self._generate_status_response(running_transformations)), 'text/json')
            else:
                add_warning(req, "No valid action found")
                req.redirect(req.href.businessintelligence())
            if req.get_header('X-Requested-With') == 'XMLHttpRequest':
                req.send_response(200)
                req.send_header('Content-Length', 0)
                req.end_headers()
                return
            else:
                if 'returnto' in req.args:
                    req.redirect(req.args['returnto'])
                else:
                    req.redirect(req.href.businessintelligence())
        else:
            req.perm.require("BUSINESSINTELLIGENCE_TRANSFORMATION_LIST")
            data = {'transformations': self._list_transformation_files(listall=False)}
            add_script(req, 'contextmenu/contextmenu.js')
            add_script(req, 'businessintelligenceplugin/js/business-intelligence.js')
            add_stylesheet(req, 'common/css/browser.css')
            add_ctxtnav(req, tag.a(tag.i(class_="fa fa-upload"), ' Upload Transformations', id="uploadbutton"))
            add_ctxtnav(req, tag.a(tag.i(class_="fa fa-calendar"), ' Schedule Transformations', id="schedulebutton"))
            add_ctxtnav(req, tag.a(tag.i(class_="fa fa-cog"), ' Running Transformations', id="runningbutton"))

            return "listtransformations.html", data, None
Beispiel #30
0
        """
        try:
            tm = self._get_ticket_module()
            req.perm.require('TICKET_CREATE')
            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)
        except Exception, exc:
            self.log.exception("BH: Quick create ticket 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

    # Public API
    def create(self, req, summary, description, attributes={}, notify=False):
Beispiel #31
0
            req.perm.require('TICKET_CREATE')
            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)
        except Exception, exc:
            self.log.exception("BH: Quick create ticket 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

    # Public API
 def _json_send(self, req, dictionary):
     return req.send(to_json(dictionary), 'text/json')