예제 #1
0
 def pretty_dateinfo(date, format=None, dateonly=False):
     if not date:
         return ''
     if format == 'date':
         absolute = user_time(req, format_date, date)
     else:
         absolute = user_time(req, format_datetime, date)
     now = datetime.datetime.now(localtz)
     relative = pretty_timedelta(date, now)
     if not format:
         format = req.session.get('dateinfo',
                                  self.default_dateinfo_format)
     in_or_ago = _("in %(relative)s", relative=relative) \
                 if date > now else \
                 _("%(relative)s ago", relative=relative)
     if format == 'relative':
         label = in_or_ago if not dateonly else relative
         title = absolute
     else:
         if dateonly:
             label = absolute
         elif req.lc_time == 'iso8601':
             label = _("at %(iso8601)s", iso8601=absolute)
         else:
             label = _("on %(date)s at %(time)s",
                       date=user_time(req, format_date, date),
                       time=user_time(req, format_time, date))
         title = in_or_ago
     return tag.span(label, title=title)
예제 #2
0
 def pretty_dateinfo(date, format=None, dateonly=False):
     absolute = user_time(req, format_datetime, date)
     relative = pretty_timedelta(date)
     if not format:
         format = req.session.get(
             'dateinfo',
             Chrome(self.env).default_dateinfo_format)
     if format == 'absolute':
         if dateonly:
             label = absolute
         elif req.lc_time == 'iso8601':
             label = _("at %(iso8601)s", iso8601=absolute)
         else:
             label = _("on %(date)s at %(time)s",
                       date=user_time(req, format_date, date),
                       time=user_time(req, format_time, date))
         title = _("See timeline %(relativetime)s ago",
                   relativetime=relative)
     else:
         label = _("%(relativetime)s ago", relativetime=relative) \
                 if not dateonly else relative
         title = _("See timeline at %(absolutetime)s",
                   absolutetime=absolute)
     return self.get_timeline_link(req,
                                   date,
                                   label,
                                   precision='second',
                                   title=title)
예제 #3
0
    def test_template_data_changes_for_time_field(self):
        self.env.config.set('ticket-custom', 'timefield', 'time')
        dt1 = datetime(2015, 7, 8, tzinfo=utc)
        dt2 = datetime(2015, 12, 11, tzinfo=utc)
        with self.env.db_transaction:
            self._insert_ticket(summary='Time fields',
                                timefield=datetime_now(utc))
            self.env.db_transaction("UPDATE ticket_custom SET value='invalid' "
                                    "WHERE ticket=1 AND name='timefield'")
            t = Ticket(self.env, 1)
            t['timefield'] = dt1
            t.save_changes('anonymous')
            t = Ticket(self.env, 1)
            t['timefield'] = dt2
            t.save_changes('anonymous')

        req = MockRequest(self.env, method='GET', path_info='/ticket/1')
        self.assertTrue(self.ticket_module.match_request(req))
        data = self.ticket_module.process_request(req)[1]
        changes = data['changes']
        dt1_text = user_time(req, format_datetime, dt1)
        dt2_text = user_time(req, format_datetime, dt2)
        self.assertEqual(2, len(changes))
        self.assertEqual('', changes[0]['fields']['timefield']['old'])
        self.assertEqual(dt1_text, changes[0]['fields']['timefield']['new'])
        self.assertEqual(dt1_text, changes[1]['fields']['timefield']['old'])
        self.assertEqual(dt2_text, changes[1]['fields']['timefield']['new'])
def get_list_pages(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    artifact_id = request.req.args.get('artifact', None)
    if artifact_id is None:
        raise Exception("No artifact was specified.")
    dbp.load_artifact(artifact_id)
    artifact = dbp.pool.get_item(artifact_id)

    results = []
    for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(artifact):
        page = WikiPage(dbp.env, pagename)

        results.append(
            {'href': get_resource_url(dbp.env, page.resource, request.req.href),
             'title': pagename,
             'date': user_time(request.req, format_datetime, page.time),
             'author': page.author,
             'excerpt': shorten_result(page.text)}
        )

    data = {
        'context': Context.from_request(request.req, resource),
        'artifact': artifact,
        'results': results,
    }
    return 'list_pages.html', data, None
예제 #5
0
    def _prepare_results(self, req, filters, results):
        page = req.args.get('page', 1)
        page = as_int(page, default=1, min=1)
        try:
            results = Paginator(results, page - 1, self.RESULTS_PER_PAGE)
        except TracError:
            add_warning(req, _("Page %(page)s is out of range.", page=page))
            page = 1
            results = Paginator(results, page - 1, self.RESULTS_PER_PAGE)

        for idx, result in enumerate(results):
            results[idx] = {
                'href': result[0],
                'title': result[1],
                'date': user_time(req, format_datetime, result[2]),
                'author': result[3],
                'excerpt': result[4]
            }

        pagedata = []
        shown_pages = results.get_shown_pages(21)
        for shown_page in shown_pages:
            page_href = req.href.search([(f, 'on') for f in filters],
                                        q=req.args.get('q'),
                                        page=shown_page,
                                        noquickjump=1)
            pagedata.append([
                page_href, None,
                str(shown_page),
                _("Page %(num)d", num=shown_page)
            ])

        fields = ['href', 'class', 'string', 'title']
        results.shown_pages = [dict(zip(fields, p)) for p in pagedata]

        results.current_page = {
            'href': None,
            'class': 'current',
            'string': str(results.page + 1),
            'title': None
        }

        if results.has_next_page:
            next_href = req.href.search(zip(filters, ['on'] * len(filters)),
                                        q=req.args.get('q'),
                                        page=page + 1,
                                        noquickjump=1)
            add_link(req, 'next', next_href, _('Next Page'))

        if results.has_previous_page:
            prev_href = req.href.search(zip(filters, ['on'] * len(filters)),
                                        q=req.args.get('q'),
                                        page=page - 1,
                                        noquickjump=1)
            add_link(req, 'prev', prev_href, _('Previous Page'))

        page_href = req.href.search(zip(filters, ['on'] * len(filters)),
                                    q=req.args.get('q'),
                                    noquickjump=1)
        return {'results': results, 'page_href': page_href}
def get_list_pages(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    artifact_id = request.req.args.get('artifact', None)
    if artifact_id is None:
        raise Exception("No artifact was specified.")
    dbp.load_artifact(artifact_id)
    artifact = dbp.pool.get_item(artifact_id)

    results = []
    for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(
            artifact):
        page = WikiPage(dbp.env, pagename)

        results.append({
            'href':
            get_resource_url(dbp.env, page.resource, request.req.href),
            'title':
            pagename,
            'date':
            user_time(request.req, format_datetime, page.time),
            'author':
            page.author,
            'excerpt':
            shorten_result(page.text)
        })

    data = {
        'context': Context.from_request(request.req, resource),
        'artifact': artifact,
        'results': results,
    }
    return 'list_pages.html', data, None
예제 #7
0
파일: main.py 프로젝트: tsanov/bloodhound
def send_project_index(environ,
                       start_response,
                       parent_dir=None,
                       env_paths=None):
    req = Request(environ, start_response)

    loadpaths = [pkg_resources.resource_filename('trac', 'templates')]
    if req.environ.get('trac.env_index_template'):
        env_index_template = req.environ['trac.env_index_template']
        tmpl_path, template = os.path.split(env_index_template)
        loadpaths.insert(0, tmpl_path)
    else:
        template = 'index.html'

    data = {
        'trac': {
            'version': TRAC_VERSION,
            'time': user_time(req, format_datetime)
        },
        'req': req
    }
    if req.environ.get('trac.template_vars'):
        for pair in req.environ['trac.template_vars'].split(','):
            key, val = pair.split('=')
            data[key] = val
    try:
        href = Href(req.base_path)
        projects = []
        for env_name, env_path in get_environments(environ).items():
            try:
                env = open_environment(env_path,
                                       use_cache=not environ['wsgi.run_once'])
                proj = {
                    'env': env,
                    'name': env.project_name,
                    'description': env.project_description,
                    'href': href(env_name)
                }
            except Exception, e:
                proj = {'name': env_name, 'description': to_unicode(e)}
            projects.append(proj)
        projects.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower()))

        data['projects'] = projects

        loader = TemplateLoader(loadpaths,
                                variable_lookup='lenient',
                                default_encoding='utf-8')
        tmpl = loader.load(template)
        stream = tmpl.generate(**data)
        if template.endswith('.xml'):
            output = stream.render('xml')
            req.send(output, 'text/xml')
        else:
            output = stream.render('xhtml',
                                   doctype=DocType.XHTML_STRICT,
                                   encoding='utf-8')
            req.send(output, 'text/html')
예제 #8
0
 def _render_link(self, context, name, label, extra=''):
     if not (name or extra):
         return tag()
     try:
         milestone = Milestone(self.env, name)
     except ResourceNotFound:
         milestone = None
     # Note: the above should really not be needed, `Milestone.exists`
     # should simply be false if the milestone doesn't exist in the db
     # (related to #4130)
     href = context.href.milestone(name)
     exists = milestone and milestone.exists
     if exists:
         if 'MILESTONE_VIEW' in context.perm(milestone.resource):
             title = None
             if hasattr(context, 'req'):
                 if milestone.is_completed:
                     title = _("Completed %(duration)s ago (%(date)s)",
                               duration=pretty_timedelta(
                                   milestone.completed),
                               date=user_time(context.req, format_datetime,
                                              milestone.completed))
                 elif milestone.is_late:
                     title = _("%(duration)s late (%(date)s)",
                               duration=pretty_timedelta(milestone.due),
                               date=user_time(context.req, format_datetime,
                                              milestone.due))
                 elif milestone.due:
                     title = _("Due in %(duration)s (%(date)s)",
                               duration=pretty_timedelta(milestone.due),
                               date=user_time(context.req, format_datetime,
                                              milestone.due))
                 else:
                     title = _("No date set")
             closed = 'closed ' if milestone.is_completed else ''
             return tag.a(label,
                          class_='%smilestone' % closed,
                          href=href + extra,
                          title=title)
     elif 'MILESTONE_CREATE' in context.perm(self.realm, name):
         return tag.a(label,
                      class_='missing milestone',
                      href=href + extra,
                      rel='nofollow')
     return tag.a(label, class_=classes('milestone', missing=not exists))
예제 #9
0
def send_project_index(environ,
                       start_response,
                       parent_dir=None,
                       env_paths=None):
    req = Request(environ, start_response)

    loadpaths = [pkg_resources.resource_filename('trac', 'templates')]
    if req.environ.get('trac.env_index_template'):
        env_index_template = req.environ['trac.env_index_template']
        tmpl_path, template = os.path.split(env_index_template)
        loadpaths.insert(0, tmpl_path)
    else:
        template = 'index.html'

    data = {
        'trac': {
            'version': TRAC_VERSION,
            'time': user_time(req, format_datetime)
        },
        'req': req
    }
    if req.environ.get('trac.template_vars'):
        for pair in req.environ['trac.template_vars'].split(','):
            key, val = pair.split('=')
            data[key] = val
    try:
        href = Href(req.base_path)
        projects = []
        for env_name, env_path in get_environments(environ).items():
            try:
                env = open_environment(env_path,
                                       use_cache=not environ['wsgi.run_once'])
                proj = {
                    'env': env,
                    'name': env.project_name,
                    'description': env.project_description,
                    'href': href(env_name)
                }
            except Exception as e:
                proj = {'name': env_name, 'description': to_unicode(e)}
            projects.append(proj)
        projects.sort(key=lambda proj: proj['name'].lower())

        data['projects'] = projects

        jenv = jinja2env(loader=FileSystemLoader(loadpaths))
        jenv.globals.update(translation.functions)
        tmpl = jenv.get_template(template)
        output = valid_html_bytes(tmpl.render(**data).encode('utf-8'))
        if template.endswith('.xml'):
            req.send(output, 'text/xml')
        else:
            req.send(output, 'text/html')

    except RequestDone:
        pass
예제 #10
0
파일: api.py 프로젝트: hanotch/trac
    def validate_ticket(self, req, ticket):
        # Validate select fields for known values.
        for field in ticket.fields:
            if 'options' not in field:
                continue
            name = field['name']
            if name == 'status':
                continue
            if name in ticket and name in ticket._old:
                value = ticket[name]
                if value:
                    if value not in field['options']:
                        yield name, _('"%(value)s" is not a valid value',
                                      value=value)
                elif not field.get('optional', False):
                    yield name, _("field cannot be empty")

        # Validate description length.
        if len(ticket['description'] or '') > self.max_description_size:
            yield 'description', _("Must be less than or equal to %(num)s "
                                   "characters",
                                   num=self.max_description_size)

        # Validate summary length.
        if not ticket['summary']:
            yield 'summary', _("Tickets must contain a summary.")
        elif len(ticket['summary'] or '') > self.max_summary_size:
            yield 'summary', _("Must be less than or equal to %(num)s "
                               "characters", num=self.max_summary_size)

        # Validate custom field length.
        for field in ticket.custom_fields:
            field_attrs = ticket.fields.by_name(field)
            max_size = field_attrs.get('max_size', 0)
            if 0 < max_size < len(ticket[field] or ''):
                label = field_attrs.get('label')
                yield label or field, _("Must be less than or equal to "
                                        "%(num)s characters", num=max_size)

        # Validate time field content.
        for field in ticket.time_fields:
            value = ticket[field]
            if field in ticket.custom_fields and \
                    field in ticket._old and \
                    not isinstance(value, datetime):
                field_attrs = ticket.fields.by_name(field)
                format = field_attrs.get('format')
                try:
                    ticket[field] = user_time(req, parse_date, value,
                                              hint=format) \
                                    if value else None
                except TracError as e:
                    # Degrade TracError to warning.
                    ticket[field] = value
                    label = field_attrs.get('label')
                    yield label or field, to_unicode(e)
예제 #11
0
파일: main.py 프로젝트: pkdevbox/trac
def send_project_index(environ, start_response, parent_dir=None,
                       env_paths=None):
    req = Request(environ, start_response)

    loadpaths = [pkg_resources.resource_filename('trac', 'templates')]
    if req.environ.get('trac.env_index_template'):
        env_index_template = req.environ['trac.env_index_template']
        tmpl_path, template = os.path.split(env_index_template)
        loadpaths.insert(0, tmpl_path)
    else:
        template = 'index.html'

    data = {'trac': {'version': TRAC_VERSION,
                     'time': user_time(req, format_datetime)},
            'req': req}
    if req.environ.get('trac.template_vars'):
        for pair in req.environ['trac.template_vars'].split(','):
            key, val = pair.split('=')
            data[key] = val
    try:
        href = Href(req.base_path)
        projects = []
        for env_name, env_path in get_environments(environ).items():
            try:
                env = open_environment(env_path,
                                       use_cache=not environ['wsgi.run_once'])
                proj = {
                    'env': env,
                    'name': env.project_name,
                    'description': env.project_description,
                    'href': href(env_name)
                }
            except Exception as e:
                proj = {'name': env_name, 'description': to_unicode(e)}
            projects.append(proj)
        projects.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower()))

        data['projects'] = projects

        loader = TemplateLoader(loadpaths, variable_lookup='lenient',
                                default_encoding='utf-8')
        tmpl = loader.load(template)
        stream = tmpl.generate(**data)
        if template.endswith('.xml'):
            output = stream.render('xml')
            req.send(output, 'text/xml')
        else:
            output = stream.render('xhtml', doctype=DocType.XHTML_STRICT,
                                   encoding='utf-8')
            req.send(output, 'text/html')

    except RequestDone:
        pass
예제 #12
0
 def _render_link(self, context, name, label, extra=''):
     if not (name or extra):
         return tag()
     try:
         milestone = Milestone(self.env, name)
     except ResourceNotFound:
         milestone = None
     # Note: the above should really not be needed, `Milestone.exists`
     # should simply be false if the milestone doesn't exist in the db
     # (related to #4130)
     href = context.href.milestone(name)
     if milestone and milestone.exists:
         if 'MILESTONE_VIEW' in context.perm(milestone.resource):
             title = None
             if hasattr(context, 'req'):
                 if milestone.is_completed:
                     title = _(
                         'Completed %(duration)s ago (%(date)s)',
                         duration=pretty_timedelta(milestone.completed),
                         date=user_time(context.req, format_datetime,
                                        milestone.completed))
                 elif milestone.is_late:
                     title = _('%(duration)s late (%(date)s)',
                               duration=pretty_timedelta(milestone.due),
                               date=user_time(context.req, format_datetime,
                                              milestone.due))
                 elif milestone.due:
                     title = _('Due in %(duration)s (%(date)s)',
                               duration=pretty_timedelta(milestone.due),
                               date=user_time(context.req, format_datetime,
                                              milestone.due))
                 else:
                     title = _('No date set')
             closed = 'closed ' if milestone.is_completed else ''
             return tag.a(label, class_='%smilestone' % closed,
                          href=href + extra, title=title)
     elif 'MILESTONE_CREATE' in context.perm(self.realm, name):
         return tag.a(label, class_='missing milestone', href=href + extra,
                      rel='nofollow')
     return tag.a(label, class_='missing milestone')
예제 #13
0
    def test_template_data_for_time_field_with_formats(self):
        gmt12 = timezone('GMT +12:00')
        req = MockRequest(self.env, method='GET', path_info='/ticket/1',
                          tz=gmt12)
        value = datetime(2016, 1, 2, 23, 34, 45, tzinfo=utc)
        expected = user_time(req, format_datetime, value)
        self.assertIn('11', expected)  # check 11 in hour part

        self._test_template_data_for_time_field(req, value, expected, None)
        self._test_template_data_for_time_field(req, value, expected,
                                                'datetime')
        self._test_template_data_for_time_field(req, value, expected,
                                                'relative')
def post_list_search_relatedpages_json(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    unparsed_spec = request.req.args.get('spec', '')
    spec_name = json.loads(unparsed_spec) if unparsed_spec else ''
    attributes = json.loads(request.req.args.get('attributes', '[]'))

    if attributes is None:
        raise Exception("No artifacts specified.")

    artifacts_array = []

    for artifact in attributes:
        try:
            dbp.load_artifact(artifact)
            full_artifact = dbp.pool.get_item(artifact)
            #artifacts_array.append(full_artifact)
            results = []
            for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(
                    full_artifact):
                page = WikiPage(dbp.env, pagename)

                results.append({
                    'href':
                    get_resource_url(dbp.env, page.resource, request.req.href),
                    'title':
                    pagename,
                    'date':
                    user_time(request.req, format_datetime, page.time),
                    'author':
                    page.author,
                    'excerpt':
                    shorten_result(page.text)
                })

            artifacts_array.append({
                'id':
                full_artifact.get_id(),
                'href':
                request.req.href.customartifacts('artifact',
                                                 full_artifact.get_id(),
                                                 action='view'),
                'title':
                unicode(full_artifact),
                'results':
                results
            })
        except ValueError:
            continue
    _return_as_json(request, artifacts_array)
    return
예제 #15
0
    def expand_macro(self, formatter, name, content):
        args, kw = parse_args(content)
        prefix = args[0].strip() if args else None
        limit = _arg_as_int(args[1].strip(), min=1) if len(args) > 1 else None
        group = kw.get('group', 'date')

        sql = """SELECT name, max(version) AS max_version,
                        max(time) AS max_time FROM wiki"""
        args = []
        if prefix:
            with self.env.db_query as db:
                sql += " WHERE name %s" % db.prefix_match()
                args.append(db.prefix_match_value(prefix))
        sql += " GROUP BY name ORDER BY max_time DESC"
        if limit:
            sql += " LIMIT %s"
            args.append(limit)

        entries_per_date = []
        prevdate = None
        for name, version, ts in self.env.db_query(sql, args):
            if not 'WIKI_VIEW' in formatter.perm('wiki', name, version):
                continue
            req = formatter.req
            date = user_time(req, format_date, from_utimestamp(ts))
            if date != prevdate:
                prevdate = date
                entries_per_date.append((date, []))
            version = int(version)
            diff_href = None
            if version > 1:
                diff_href = formatter.href.wiki(name, action='diff',
                                                version=version)
            page_name = formatter.wiki.format_page_name(name)
            entries_per_date[-1][1].append((page_name, name, version,
                                            diff_href))

        items_per_date = (
            (date, (tag.li(tag.a(page, href=formatter.href.wiki(name)),
                           tag.small(' (', tag.a(_("diff"), href=diff_href),
                                     ')') if diff_href else None,
                           '\n')
                    for page, name, version, diff_href in entries))
            for date, entries in entries_per_date)

        if group == 'date':
            out = ((tag.h3(date), tag.ul(entries))
                   for date, entries in items_per_date)
        else:
            out = tag.ul(entries for date, entries in items_per_date)
        return tag.div(out)
예제 #16
0
파일: macros.py 프로젝트: exocad/exotrac
    def expand_macro(self, formatter, name, content):
        args, kw = parse_args(content)
        prefix = args[0].strip() if args else None
        limit = int(args[1].strip()) if len(args) > 1 else None
        group = kw.get('group', 'date')

        sql = """SELECT name, max(version) AS max_version,
                        max(time) AS max_time FROM wiki"""
        args = []
        if prefix:
            with self.env.db_query as db:
                sql += " WHERE name %s" % db.prefix_match()
                args.append(db.prefix_match_value(prefix))
        sql += " GROUP BY name ORDER BY max_time DESC"
        if limit:
            sql += " LIMIT %s"
            args.append(limit)

        entries_per_date = []
        prevdate = None
        for name, version, ts in self.env.db_query(sql, args):
            if not 'WIKI_VIEW' in formatter.perm('wiki', name, version):
                continue
            req = formatter.req
            date = user_time(req, format_date, from_utimestamp(ts))
            if date != prevdate:
                prevdate = date
                entries_per_date.append((date, []))
            version = int(version)
            diff_href = None
            if version > 1:
                diff_href = formatter.href.wiki(name, action='diff',
                                                version=version)
            page_name = formatter.wiki.format_page_name(name)
            entries_per_date[-1][1].append((page_name, name, version,
                                            diff_href))

        items_per_date = (
            (date, (tag.li(tag.a(page, href=formatter.href.wiki(name)),
                           tag.small(' (', tag.a(_("diff"), href=diff_href),
                                     ')') if diff_href else None,
                           '\n')
                    for page, name, version, diff_href in entries))
            for date, entries in entries_per_date)

        if group == 'date':
            out = ((tag.h3(date), tag.ul(entries))
                   for date, entries in items_per_date)
        else:
            out = tag.ul(entries for date, entries in items_per_date)
        return tag.div(out)
예제 #17
0
 def pretty_dateinfo(date, format=None, dateonly=False):
     absolute = user_time(req, format_datetime, date)
     relative = pretty_timedelta(date)
     if not format:
         format = req.session.get('dateinfo',
                      Chrome(self.env).default_dateinfo_format)
     if format == 'absolute':
         if dateonly:
             label = absolute
         elif req.lc_time == 'iso8601':
             label = _("at %(iso8601)s", iso8601=absolute)
         else:
             label = _("on %(date)s at %(time)s",
                       date=user_time(req, format_date, date),
                       time=user_time(req, format_time, date))
         title = _("See timeline %(relativetime)s ago",
                   relativetime=relative)
     else:
         label = _("%(relativetime)s ago", relativetime=relative) \
                 if not dateonly else relative
         title = _("See timeline at %(absolutetime)s",
                   absolutetime=absolute)
     return self.get_timeline_link(req, date, label,
                                   precision='second', title=title)
예제 #18
0
    def expand_macro(self, formatter, name, content):
        prefix = limit = None
        if content:
            argv = [arg.strip() for arg in content.split(',')]
            if len(argv) > 0:
                prefix = argv[0]
                if len(argv) > 1:
                    limit = int(argv[1])

        sql = """SELECT name, max(version) AS max_version, 
                        max(time) AS max_time FROM wiki"""
        args = []
        if prefix:
            sql += " WHERE name LIKE %s"
            args.append(prefix + '%')
        sql += " GROUP BY name ORDER BY max_time DESC"
        if limit:
            sql += " LIMIT %s"
            args.append(limit)

        entries_per_date = []
        prevdate = None
        for name, version, ts in self.env.db_query(sql, args):
            if not 'WIKI_VIEW' in formatter.perm('wiki', name, version):
                continue
            req = formatter.req
            date = user_time(req, format_date, from_utimestamp(ts))
            if date != prevdate:
                prevdate = date
                entries_per_date.append((date, []))
            version = int(version)
            diff_href = None
            if version > 1:
                diff_href = formatter.href.wiki(name,
                                                action='diff',
                                                version=version)
            page_name = formatter.wiki.format_page_name(name)
            entries_per_date[-1][1].append(
                (page_name, name, version, diff_href))
        return tag.div(
            (tag.h3(date),
             tag.ul(
                 tag.li(
                     tag.a(page, href=formatter.href.wiki(name)),
                     ' ', diff_href and tag.small(
                         '(', tag.a('diff', href=diff_href), ')') or None)
                 for page, name, version, diff_href in entries))
            for date, entries in entries_per_date)
예제 #19
0
    def expand_macro(self, formatter, name, content):
        prefix = limit = None
        if content:
            argv = [arg.strip() for arg in content.split(',')]
            if len(argv) > 0:
                prefix = argv[0]
                if len(argv) > 1:
                    limit = int(argv[1])

        sql = """SELECT name, max(version) AS max_version, 
                        max(time) AS max_time FROM wiki"""
        args = []
        if prefix:
            sql += " WHERE name LIKE %s"
            args.append(prefix + '%')
        sql += " GROUP BY name ORDER BY max_time DESC"
        if limit:
            sql += " LIMIT %s"
            args.append(limit)

        entries_per_date = []
        prevdate = None
        for name, version, ts in self.env.db_query(sql, args):
            if not 'WIKI_VIEW' in formatter.perm('wiki', name, version):
                continue
            req = formatter.req
            date = user_time(req, format_date, from_utimestamp(ts))
            if date != prevdate:
                prevdate = date
                entries_per_date.append((date, []))
            version = int(version)
            diff_href = None
            if version > 1:
                diff_href = formatter.href.wiki(name, action='diff',
                                                version=version)
            page_name = formatter.wiki.format_page_name(name)
            entries_per_date[-1][1].append((page_name, name, version,
                                            diff_href))
        return tag.div(
            (tag.h3(date),
             tag.ul(
                 tag.li(tag.a(page, href=formatter.href.wiki(name)), ' ',
                        diff_href and
                        tag.small('(', tag.a('diff', href=diff_href), ')') or
                        None)
                 for page, name, version, diff_href in entries))
            for date, entries in entries_per_date)
예제 #20
0
    def render_admin_panel(self, req, cat, page, path_info):
        assert req.perm.has_permission('TRAC_ADMIN')

        action = req.args.get('action', 'view')
        if req.method == 'POST':
            confirm = req.args.get('confirm', 0)
            if 'purge_threshold' in req.args:
                purge_threshold_str = req.args.get('purge_threshold', '')
                purge_threshold = user_time(req, parse_date, purge_threshold_str, hint='datetime') \
                                if purge_threshold_str else None
            else:
                purge_threshold = None

            if not confirm:
                self.log.debug('render_admin_panel purge not yet confirmed')
                if purge_threshold is not None:
                    crashes = CrashDump.query_old_data(self.env,
                                                       purge_threshold)
                data = {
                    'datetime_hint': get_datetime_format_hint(req.lc_time),
                    'purge_threshold': purge_threshold_str,
                    'purge_crashes': crashes
                }
                return 'crashdump_admin_%s.html' % page, data
            elif confirm == 'no':
                self.log.debug('render_admin_panel purge canceled')
                req.redirect(req.href.admin(cat, page))
            elif confirm == 'yes':
                self.log.debug('render_admin_panel purge confirmed')
                req.redirect(req.href.admin(cat, page))
        else:
            now = datetime.now(req.tz)

            purge_threshold = datetime(now.year, now.month, now.day, 0)
            purge_threshold -= timedelta(days=365)
            data = {
                'datetime_hint': get_datetime_format_hint(req.lc_time),
                'purge_threshold': purge_threshold,
                'purge_crashes': None,
            }
            print('crashdump_admin_%s.html' % page, data)
            return 'crashdump_admin_%s.html' % page, data
예제 #21
0
    def _process_doc(self, doc):
        ui_doc = dict(doc)
        if doc['product']:
            product_href = ProductEnvironment(self.env, doc['product']).href
            # pylint: disable=too-many-function-args
            ui_doc["href"] = product_href(doc['type'], doc['id'])
        else:
            ui_doc["href"] = self.req.href(doc['type'], doc['id'])

        if doc['content']:
            ui_doc['content'] = shorten_result(doc['content'])

        if doc['time']:
            ui_doc['date'] = user_time(self.req, format_datetime, doc['time'])

        is_free_text_view = self.view is None
        if is_free_text_view:
            participant = self.allowed_participants[doc['type']]
            ui_doc['title'] = participant.format_search_results(doc)
        return ui_doc
예제 #22
0
    def _process_doc(self, doc):
        ui_doc = dict(doc)
        if doc['product']:
            product_href = ProductEnvironment(self.env, doc['product']).href
            # pylint: disable=too-many-function-args
            ui_doc["href"] = product_href(doc['type'], doc['id'])
        else:
            ui_doc["href"] = self.req.href(doc['type'], doc['id'])

        if doc['content']:
            ui_doc['content'] = shorten_result(doc['content'])

        if doc['time']:
            ui_doc['date'] = user_time(self.req, format_datetime, doc['time'])

        is_free_text_view = self.view is None
        if is_free_text_view:
            participant = self.allowed_participants[doc['type']]
            ui_doc['title'] = participant.format_search_results(doc)
        return ui_doc
예제 #23
0
    def test_template_data_for_time_field_with_date_format(self):
        value = datetime(2016, 2, 22, 22, 22, 22, tzinfo=utc)
        self.env.config.set('ticket-custom', 'timefield', 'time')
        self.env.config.set('ticket-custom', 'timefield.format', 'date')
        self._insert_ticket(summary='Time fields', timefield=value)
        self.assertEqual(value, Ticket(self.env, 1)['timefield'])

        gmt12 = timezone('GMT +12:00')
        req = MockRequest(self.env, method='GET', path_info='/ticket/1',
                          tz=gmt12)
        expected = user_time(req, format_date, value)
        self.assertIn('23', expected)  # check 23 in day part
        self.assertTrue(self.ticket_module.match_request(req))
        data = self.ticket_module.process_request(req)[1]

        for f in data['fields']:
            if f['name'] == 'timefield':
                self.assertEqual(expected, f['edit'])
                break
        else:
            self.fail('Missing timefield field')
예제 #24
0
    def _prepare_results(self, req, filters, results):
        page = int(req.args.get('page', '1'))
        results = Paginator(results, page - 1, self.RESULTS_PER_PAGE)
        for idx, result in enumerate(results):
            results[idx] = {'href': result[0], 'title': result[1],
                            'date': user_time(req, format_datetime, result[2]),
                            'author': result[3], 'excerpt': result[4]}

        pagedata = []
        shown_pages = results.get_shown_pages(21)
        for shown_page in shown_pages:
            page_href = req.href.search([(f, 'on') for f in filters],
                                        q=req.args.get('q'),
                                        page=shown_page, noquickjump=1)
            pagedata.append([page_href, None, str(shown_page),
                             'page ' + str(shown_page)])

        fields = ['href', 'class', 'string', 'title']
        results.shown_pages = [dict(zip(fields, p)) for p in pagedata]

        results.current_page = {'href': None, 'class': 'current',
                                'string': str(results.page + 1),
                                'title':None}

        if results.has_next_page:
            next_href = req.href.search(zip(filters, ['on'] * len(filters)),
                                        q=req.args.get('q'), page=page + 1,
                                        noquickjump=1)
            add_link(req, 'next', next_href, _('Next Page'))

        if results.has_previous_page:
            prev_href = req.href.search(zip(filters, ['on'] * len(filters)),
                                        q=req.args.get('q'), page=page - 1,
                                        noquickjump=1)
            add_link(req, 'prev', prev_href, _('Previous Page'))

        page_href = req.href.search(
            zip(filters, ['on'] * len(filters)), q=req.args.get('q'),
            noquickjump=1)
        return {'results': results, 'page_href': page_href}
예제 #25
0
    def process_request(self, req):
        req.perm.assert_permission('TIMELINE_VIEW')

        format = req.args.get('format')
        maxrows = int(req.args.get('max', 50 if format == 'rss' else 0))
        lastvisit = int(req.session.get('timeline.lastvisit', '0'))

        # indication of new events is unchanged when form is updated by user
        revisit = any(a in req.args
                      for a in ['update', 'from', 'daysback', 'author'])
        if revisit:
            lastvisit = int(
                req.session.get('timeline.nextlastvisit', lastvisit))

        # Parse the from date and adjust the timestamp to the last second of
        # the day
        fromdate = today = datetime_now(req.tz)
        yesterday = to_datetime(
            today.replace(tzinfo=None) - timedelta(days=1), req.tz)
        precisedate = precision = None
        if 'from' in req.args:
            # Acquire from date only from non-blank input
            reqfromdate = req.args['from'].strip()
            if reqfromdate:
                try:
                    precisedate = user_time(req, parse_date, reqfromdate)
                except TracError, e:
                    add_warning(req, e)
                else:
                    fromdate = precisedate.astimezone(req.tz)
            precision = req.args.get('precision', '')
            if precision.startswith('second'):
                precision = timedelta(seconds=1)
            elif precision.startswith('minute'):
                precision = timedelta(minutes=1)
            elif precision.startswith('hour'):
                precision = timedelta(hours=1)
            else:
                precision = None
예제 #26
0
파일: web_ui.py 프로젝트: exocad/exotrac
    def _prepare_results(self, req, filters, results):
        page = int(req.args.get("page", "1"))
        results = Paginator(results, page - 1, self.RESULTS_PER_PAGE)
        for idx, result in enumerate(results):
            results[idx] = {
                "href": result[0],
                "title": result[1],
                "date": user_time(req, format_datetime, result[2]),
                "author": result[3],
                "excerpt": result[4],
            }

        pagedata = []
        shown_pages = results.get_shown_pages(21)
        for shown_page in shown_pages:
            page_href = req.href.search(
                [(f, "on") for f in filters], q=req.args.get("q"), page=shown_page, noquickjump=1
            )
            pagedata.append([page_href, None, str(shown_page), _("Page %(num)d", num=shown_page)])

        fields = ["href", "class", "string", "title"]
        results.shown_pages = [dict(zip(fields, p)) for p in pagedata]

        results.current_page = {"href": None, "class": "current", "string": str(results.page + 1), "title": None}

        if results.has_next_page:
            next_href = req.href.search(
                zip(filters, ["on"] * len(filters)), q=req.args.get("q"), page=page + 1, noquickjump=1
            )
            add_link(req, "next", next_href, _("Next Page"))

        if results.has_previous_page:
            prev_href = req.href.search(
                zip(filters, ["on"] * len(filters)), q=req.args.get("q"), page=page - 1, noquickjump=1
            )
            add_link(req, "prev", prev_href, _("Previous Page"))

        page_href = req.href.search(zip(filters, ["on"] * len(filters)), q=req.args.get("q"), noquickjump=1)
        return {"results": results, "page_href": page_href}
예제 #27
0
    def render_admin_panel(self, req, cat, page, path_info):
        assert req.perm.has_permission('TRAC_ADMIN')

        action = req.args.get('action', 'view')
        if req.method == 'POST':
            confirm = req.args.get('confirm', 0)
            if 'purge_threshold' in req.args:
                purge_threshold_str = req.args.get('purge_threshold', '')
                purge_threshold = user_time(req, parse_date, purge_threshold_str, hint='datetime') \
                                if purge_threshold_str else None
            else:
                purge_threshold = None

            if not confirm:
                self.log.debug('render_admin_panel purge not yet confirmed')
                if purge_threshold is not None:
                    crashes = CrashDump.query_old_data(self.env, purge_threshold)
                data = {
                    'datetime_hint': get_datetime_format_hint(req.lc_time),
                    'purge_threshold': purge_threshold_str,
                    'purge_crashes': crashes
                }
                return 'crashdump_admin_%s.html' % page, data
            elif confirm == 'no':
                self.log.debug('render_admin_panel purge canceled')
                req.redirect(req.href.admin(cat, page))
            elif confirm == 'yes':
                self.log.debug('render_admin_panel purge confirmed')
                req.redirect(req.href.admin(cat, page))
        else:
            now = datetime.now(req.tz)

            purge_threshold = datetime(now.year, now.month, now.day, 0)
            purge_threshold -= timedelta(days=365)
            data = {
                'datetime_hint': get_datetime_format_hint(req.lc_time),
                'purge_threshold': purge_threshold,
            }
            return 'crashdump_admin_%s.html' % page, data
예제 #28
0
파일: web_ui.py 프로젝트: exocad/exotrac
    def process_request(self, req):
        req.perm.assert_permission('TIMELINE_VIEW')

        format = req.args.get('format')
        maxrows = int(req.args.get('max', 50 if format == 'rss' else 0))
        lastvisit = int(req.session.get('timeline.lastvisit', '0'))

        # indication of new events is unchanged when form is updated by user
        revisit = any(a in req.args for a in ['update', 'from', 'daysback',
                                              'author'])
        if revisit:
            lastvisit = int(req.session.get('timeline.nextlastvisit',
                                            lastvisit))

        # Parse the from date and adjust the timestamp to the last second of
        # the day
        fromdate = today = datetime.now(req.tz)
        yesterday = to_datetime(today.replace(tzinfo=None) - timedelta(days=1),
                                req.tz)
        precisedate = precision = None
        if 'from' in req.args:
            # Acquire from date only from non-blank input
            reqfromdate = req.args['from'].strip()
            if reqfromdate:
                try:
                    precisedate = user_time(req, parse_date, reqfromdate)
                except TracError, e:
                    add_warning(req, e)
                else:
                    fromdate = precisedate.astimezone(req.tz)
            precision = req.args.get('precision', '')
            if precision.startswith('second'):
                precision = timedelta(seconds=1)
            elif precision.startswith('minute'):
                precision = timedelta(minutes=1)
            elif precision.startswith('hour'):
                precision = timedelta(hours=1)
            else:
                precision = None
def post_list_search_relatedpages_json(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    unparsed_spec = request.req.args.get('spec', '')
    spec_name = json.loads(unparsed_spec) if unparsed_spec else ''
    attributes = json.loads(request.req.args.get('attributes', '[]'))

    if attributes is None:
        raise Exception("No artifacts specified.")

    artifacts_array = []

    for artifact in attributes:
        try:
            dbp.load_artifact(artifact)
            full_artifact = dbp.pool.get_item(artifact)
            #artifacts_array.append(full_artifact)
            results = []
            for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(full_artifact):
                page = WikiPage(dbp.env, pagename)

                results.append(
                    {'href': get_resource_url(dbp.env, page.resource, request.req.href),
                     'title': pagename,
                     'date': user_time(request.req, format_datetime, page.time),
                     'author': page.author,
                     'excerpt': shorten_result(page.text)}
                )

            artifacts_array.append(
                {'id': full_artifact.get_id(),
                 'href': request.req.href.customartifacts('artifact', full_artifact.get_id(), action='view'),
                 'title': unicode(full_artifact),
                 'results' : results})
        except ValueError:
            continue
    _return_as_json(request, artifacts_array)
    return
def get_view_artifact(request, dbp, obj, resource):
    require_permission(request.req, resource, dbp.env)

    artifact_url = request.req.href.customartifacts('artifact/{0}'.format(obj.get_id()))
    spec_name, spec_url, values = _get_artifact_details(obj, request.req)

    # Getting wiki pages that refer the artifact
    related_pages = []
    from trac.wiki.formatter import OutlineFormatter
    from trac.web.chrome import web_context

    class NullOut(object):
        def write(self, *args): pass

    for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(obj):
        page = WikiPage(dbp.env, pagename)

        fmt = OutlineFormatter(dbp.env, web_context(request.req))
        fmt.format(page.text, NullOut())
        title = ''
        text = page.text
        if fmt.outline:
            title = fmt.outline[0][2]
            text = re.sub('[=]+[ ]+' + title + '[ ]+[=]+\s?','', text)

        related_pages.append(
            {'href': get_resource_url(dbp.env, page.resource, request.req.href),
             'title': title if title else pagename,
             'date': user_time(request.req, format_datetime, page.time),
             'author': page.author,
             'excerpt': shorten_result(text)})

    # Getting artifacts that this artifact refers to
    referred_artifacts = []
    from AdaptiveArtifacts import get_artifact_id_names_from_text
    for attribute_name, value in obj.get_values():
        for related_artifact_id,related_artifact_text in get_artifact_id_names_from_text(unicode(value)):
            if dbp.pool.get_item(related_artifact_id) is None:
                dbp.load_artifact(related_artifact_id)
            referred_artifacts.append((dbp.pool.get_item(related_artifact_id),  "%s (%s)" % (related_artifact_text, attribute_name)))

    # Getting artifacts whose attribute values refer this artifact
    referring_artifacts = []
    for related_artifact_id, related_artifact_version_id, ref_count in dbp.get_related_artifact_ref_counts(obj):
        if dbp.pool.get_item(related_artifact_id) is None:
            dbp.load_artifact(related_artifact_id)
        artifact = dbp.pool.get_item(related_artifact_id)

        url = request.req.href.customartifacts('artifact/%d' % (artifact.get_id(),), action='view')
        rel_spec_name = artifact.__class__.get_name() if not artifact.__class__ is Instance else None
        rel_spec_url = request.req.href.customartifacts('spec', artifact.__class__.get_id(), action='view'),
        id_version, time, author, ipnr, comment, readonly = dbp.get_latest_version_details(artifact.get_id())
        referring_artifacts.append(
            {'href': url,
             'spec_name': rel_spec_name,
             'spec_url': rel_spec_url,
             'author': author,
             'date': user_time(request.req, format_datetime, time),
             'artifact': artifact}
        )

    # Build yuml url
    class YUMLDiagram(object):
        def __init__(self):
            self.classes = []
            self.base_url = "http://yuml.me/diagram/plain/class/"
            self._diagram = ""
            self.is_incomplete = False

        def add_class(self, header, body, associations):
            self.classes.append({'header': header, 'body': body, 'associations': associations})

        def serialize(self):
            for yuml_class in self.classes:
                yuml_fragment = "[" + yuml_class['header']
                if yuml_class['body']:
                    yuml_fragment += "|" + ";".join(yuml_class['body'])
                yuml_fragment += "],"
                self._diagram += yuml_fragment

                if yuml_class['associations']:
                    for association_target,association_label, in yuml_class['associations']:
                        yuml_fragment = "[%s]-%s>[%s]," % (yuml_class['header'], association_label, association_target)
                        self._diagram += yuml_fragment

        def get_dsl_text(self):
            return self._diagram.encode('utf8').replace(" ", "&nbsp;")

        def get_url(self):
            #Could be used for GET requests, as long as it doesn't exceed the maximum URL size
            #return self.base_url + quote(self.get_dsl_text(), "[],;:->=")
            from urllib2 import Request, urlopen
            from urllib import urlencode
            try:
                image_filename = urlopen(Request(yuml.base_url, data=urlencode({'dsl_text': yuml.get_dsl_text()}))).read()
            except HTTPError:
                return ""
            return self.base_url + image_filename

    yuml = YUMLDiagram()

    def artifact_to_yuml_class(rel_artifact, include_values=True):
        def sanitize(value):
            if type(value) == list:
                value = ",".join(value)
            for i, j in {"[": "(",
                         "]": ")",
                         ",": ".",
                         ";": ".",
                         "->": "-",
                         "|": "\\",
                         }.iteritems():
                value = value.replace(i, j)
            return value if len(value) < 128 else "..."

        rel_artifact_title = unicode(rel_artifact)
        rel_spec_name = (u" : " + rel_artifact.__class__.get_name()) if not rel_artifact.__class__ is Instance else u""
        header = rel_artifact_title + rel_spec_name
        body = []
        if include_values:
            for attribute_name, value in rel_artifact.get_values():
                body.append("%s = %s" % (sanitize(attribute_name), sanitize(value)))
        return {'header': sanitize(header), 'body': body, 'associations': []}

    yuml_class = artifact_to_yuml_class(obj)
    yuml_class['body'].append('{bg:orange}') # color the main artifact differently
    yuml_class['associations'] = [(artifact_to_yuml_class(rel_artifact, False)['header'], rel_artifact_text) for rel_artifact, rel_artifact_text in referred_artifacts]
    yuml.add_class(**yuml_class)

    for rel_artifact in referring_artifacts:
        rel_yuml_class = artifact_to_yuml_class(rel_artifact['artifact'])
        rel_yuml_class['associations'] = [(artifact_to_yuml_class(obj, False)['header'], "")]
        yuml.add_class(**rel_yuml_class)

    yuml.serialize()

    # track access
    dbp.track_it("artifact", obj.get_id(), "view", request.req.authname, str(datetime.now()))

    data = {
        'context': Context.from_request(request.req, resource),
        'spec_name': spec_name,
        'spec_url': spec_url,
        'artifact': obj,
        'artifact_url': artifact_url,
        'artifacts_values': values,
        'related_pages': related_pages,
        'related_artifacts': referring_artifacts,
        'show_diagram': dbp.env.config.getbool('asa', 'show_diagram', default=True),
        'yuml_url': yuml.get_url(),
    }
    return 'view_artifact_%s.html' % (request.get_format(),), data, None
예제 #31
0
    def process_request(self, req):
        """Process the request
        """
        base = self.get_mypage_base(req.authname)
        tzinfo = getattr(req, 'tz', None)
        now = datetime.now(tzinfo or localtz)
        today = format_date(now, 'iso8601', tzinfo)
        today_page_name = base + today
        today_page = WikiPage(self.env, today_page_name)
        if today_page.exists:
            req.redirect(req.href.wiki(today_page_name, action='edit'))

        # create page of the day for today
        if 'WIKI_CREATE' not in req.perm(today_page.resource):
            raise ResourceNotFound(_("Can't create the page of the day."))
        ws = WikiSystem(self.env)
        def get_page_text(pagename):
            if ws.has_page(pagename):
                page = WikiPage(self.env, pagename)
                if 'WIKI_VIEW' in req.perm(page.resource):
                    self.log.debug("get_page_text(%s) -> %s",
                                   pagename, page.text)
                    return page.text
            self.log.debug("get_page_text(%s) -> None", pagename)

        # retrieve page template
        template_name = 'PageTemplates/MyPage'
        mytemplate_name = '/'.join([template_name, req.authname])
        template_text = get_page_text(mytemplate_name)
        if template_text is None:
            template_text = get_page_text(template_name)

        text = last_page_text = last_page_quoted = None
        if template_text is not None:
            # retrieve previous "page of the day", if any
            all_mypages = self.get_all_mypages(base)
            last = bisect(all_mypages, today_page_name) - 1
            self.log.debug("Pos of today %s in %r is %d",
                           today_page_name, all_mypages, last)
            last_page_name = all_mypages[last] if last >= 0 else None
            last_page_link = ''
            if last_page_name:
                last_page_link = '[[%s]]' % last_page_name
                last_page_text = get_page_text(last_page_name)
                if last_page_text is not None:
                    last_page_quoted = '\n'.join(
                        ['> ' + line for line in last_page_text.splitlines()])

            today_user = user_time(req, format_date, now, tzinfo=tzinfo)
            author = get_reporter_id(req)

            text = template_text \
                .replace(self.tokens['date'][0], today_user) \
                .replace(self.tokens['isodate'][0], today) \
                .replace(self.tokens['user'][0], req.authname) \
                .replace(self.tokens['author'][0], author) \
                .replace(self.tokens['lp_link'][0], last_page_link) \
                .replace(self.tokens['lp_name'][0], last_page_name or '') \
                .replace(self.tokens['lp_text'][0], last_page_text or '') \
                .replace(self.tokens['lp_quoted'][0], last_page_quoted or '')
        req.redirect(req.href.wiki(today_page_name, action='edit', text=text))
예제 #32
0
파일: web_ui.py 프로젝트: pkdevbox/trac
    def process_request(self, req):
        req.perm('timeline').require('TIMELINE_VIEW')

        format = req.args.get('format')
        maxrows = int(req.args.get('max', 50 if format == 'rss' else 0))
        lastvisit = int(req.session.get('timeline.lastvisit', '0'))

        # indication of new events is unchanged when form is updated by user
        revisit = any(a in req.args
                      for a in ['update', 'from', 'daysback', 'author'])
        if revisit:
            lastvisit = int(req.session.get('timeline.nextlastvisit',
                                            lastvisit))

        # Parse the from date and adjust the timestamp to the last second of
        # the day
        fromdate = today = datetime.now(req.tz)
        yesterday = to_datetime(today.replace(tzinfo=None) - timedelta(days=1),
                                req.tz)
        precisedate = precision = None
        if 'from' in req.args:
            # Acquire from date only from non-blank input
            reqfromdate = req.args['from'].strip()
            if reqfromdate:
                try:
                    precisedate = user_time(req, parse_date, reqfromdate)
                except TracError as e:
                    add_warning(req, e)
                else:
                    fromdate = precisedate.astimezone(req.tz)
            precision = req.args.get('precision', '')
            if precision.startswith('second'):
                precision = timedelta(seconds=1)
            elif precision.startswith('minute'):
                precision = timedelta(minutes=1)
            elif precision.startswith('hour'):
                precision = timedelta(hours=1)
            else:
                precision = None
        fromdate = to_datetime(datetime(fromdate.year, fromdate.month,
                                        fromdate.day, 23, 59, 59, 999999),
                               req.tz)

        daysback = as_int(req.args.get('daysback'),
                          90 if format == 'rss' else None)
        if daysback is None:
            daysback = as_int(req.session.get('timeline.daysback'), None)
        if daysback is None:
            daysback = self.default_daysback
        daysback = max(0, daysback)
        if self.max_daysback >= 0:
            daysback = min(self.max_daysback, daysback)

        authors = req.args.get('authors')
        if authors is None and format != 'rss':
            authors = req.session.get('timeline.authors')
        authors = (authors or '').strip()

        data = {'fromdate': fromdate, 'daysback': daysback,
                'authors': authors,
                'today': user_time(req, format_date, today),
                'yesterday': user_time(req, format_date, yesterday),
                'precisedate': precisedate, 'precision': precision,
                'events': [], 'filters': [],
                'abbreviated_messages': self.abbreviated_messages,
                'lastvisit': lastvisit}

        available_filters = []
        for event_provider in self.event_providers:
            available_filters += event_provider.get_timeline_filters(req) or []

        # check the request or session for enabled filters, or use default
        filters = [f[0] for f in available_filters if f[0] in req.args]
        if not filters and format != 'rss':
            filters = [f[0] for f in available_filters
                       if req.session.get('timeline.filter.' + f[0]) == '1']
        if not filters:
            filters = [f[0] for f in available_filters if len(f) == 2 or f[2]]

        # save the results of submitting the timeline form to the session
        if 'update' in req.args:
            for filter_ in available_filters:
                key = 'timeline.filter.%s' % filter_[0]
                if filter_[0] in req.args:
                    req.session[key] = '1'
                elif key in req.session:
                    del req.session[key]

        stop = fromdate
        start = to_datetime(stop.replace(tzinfo=None) -
                            timedelta(days=daysback + 1), req.tz)

        # create author include and exclude sets
        include = set()
        exclude = set()
        for match in self._authors_pattern.finditer(authors):
            name = (match.group(2) or match.group(3) or match.group(4)).lower()
            if match.group(1):
                exclude.add(name)
            else:
                include.add(name)

        # gather all events for the given period of time
        events = []
        for provider in self.event_providers:
            try:
                for event in provider.get_timeline_events(req, start, stop,
                                                          filters) or []:
                    author = (event[2] or '').lower()
                    if (not include or author in include) \
                            and author not in exclude:
                        events.append(self._event_data(provider, event))
            except Exception as e:  # cope with a failure of that provider
                self._provider_failure(e, req, provider, filters,
                                       [f[0] for f in available_filters])

        # prepare sorted global list
        events = sorted(events, key=lambda e: e['date'], reverse=True)
        if maxrows:
            events = events[:maxrows]

        data['events'] = events

        if format == 'rss':
            rss_context = web_context(req, absurls=True)
            rss_context.set_hints(wiki_flavor='html', shorten_lines=False)
            data['context'] = rss_context
            return 'timeline.rss', data, 'application/rss+xml'
        else:
            req.session.set('timeline.daysback', daysback,
                            self.default_daysback)
            req.session.set('timeline.authors', authors, '')
            # store lastvisit
            if events and not revisit:
                lastviewed = to_utimestamp(events[0]['date'])
                req.session['timeline.lastvisit'] = max(lastvisit, lastviewed)
                req.session['timeline.nextlastvisit'] = lastvisit
            html_context = web_context(req)
            html_context.set_hints(wiki_flavor='oneliner',
                                   shorten_lines=self.abbreviated_messages)
            data['context'] = html_context

        add_stylesheet(req, 'common/css/timeline.css')
        rss_href = req.href.timeline([(f, 'on') for f in filters],
                                     daysback=90, max=50, authors=authors,
                                     format='rss')
        add_link(req, 'alternate', auth_link(req, rss_href), _('RSS Feed'),
                 'application/rss+xml', 'rss')
        Chrome(self.env).add_jquery_ui(req)

        for filter_ in available_filters:
            data['filters'].append({'name': filter_[0], 'label': filter_[1],
                                    'enabled': filter_[0] in filters})

        # Navigation to the previous/next period of 'daysback' days
        previous_start = fromdate.replace(tzinfo=None) - \
                         timedelta(days=daysback + 1)
        previous_start = format_date(to_datetime(previous_start, req.tz),
                                     format='%Y-%m-%d', tzinfo=req.tz)
        add_link(req, 'prev', req.href.timeline(from_=previous_start,
                                                authors=authors,
                                                daysback=daysback),
                 _("Previous Period"))
        if today - fromdate > timedelta(days=0):
            next_start = fromdate.replace(tzinfo=None) + \
                         timedelta(days=daysback + 1)
            next_start = format_date(to_datetime(next_start, req.tz),
                                     format='%Y-%m-%d', tzinfo=req.tz)
            add_link(req, 'next', req.href.timeline(from_=next_start,
                                                    authors=authors,
                                                    daysback=daysback),
                     _("Next Period"))
        prevnext_nav(req, _("Previous Period"), _("Next Period"))

        return 'timeline.html', data, None
예제 #33
0
파일: web_ui.py 프로젝트: rwbaumg/trac
    def process_request(self, req):
        req.perm('timeline').require('TIMELINE_VIEW')

        format = req.args.get('format')
        maxrows = req.args.getint('max', 50 if format == 'rss' else 0)
        lastvisit = req.session.as_int('timeline.lastvisit', 0)

        # indication of new events is unchanged when form is updated by user
        revisit = any(a in req.args
                      for a in ['update', 'from', 'daysback', 'author'])
        if revisit:
            lastvisit = req.session.as_int('timeline.nextlastvisit',
                                           lastvisit)

        # Parse the from date and adjust the timestamp to the last second of
        # the day
        fromdate = datetime_now(req.tz)
        today = truncate_datetime(fromdate)
        yesterday = to_datetime(today.replace(tzinfo=None) - timedelta(days=1),
                                req.tz)
        precisedate = precision = None
        if 'from' in req.args:
            # Acquire from date only from non-blank input
            reqfromdate = req.args.get('from').strip()
            if reqfromdate:
                try:
                    precisedate = user_time(req, parse_date, reqfromdate)
                except TracError as e:
                    add_warning(req, e)
                else:
                    fromdate = precisedate.astimezone(req.tz)
            precision = req.args.get('precision', '')
            if precision.startswith('second'):
                precision = timedelta(seconds=1)
            elif precision.startswith('minute'):
                precision = timedelta(minutes=1)
            elif precision.startswith('hour'):
                precision = timedelta(hours=1)
            else:
                precision = None
        fromdate = to_datetime(datetime(fromdate.year, fromdate.month,
                                        fromdate.day, 23, 59, 59, 999999),
                               req.tz)

        pref = req.session.as_int('timeline.daysback', self.default_daysback)
        default = 90 if format == 'rss' else pref
        daysback = req.args.as_int('daysback', default,
                                   min=1, max=self.max_daysback)

        authors = req.args.get('authors')
        if authors is None and format != 'rss':
            authors = req.session.get('timeline.authors')
        authors = (authors or '').strip()

        data = {'fromdate': fromdate, 'daysback': daysback,
                'authors': authors, 'today': today, 'yesterday': yesterday,
                'precisedate': precisedate, 'precision': precision,
                'events': [], 'filters': [],
                'abbreviated_messages': self.abbreviated_messages}

        available_filters = []
        for event_provider in self.event_providers:
            with component_guard(self.env, req, event_provider):
                available_filters += (event_provider.get_timeline_filters(req)
                                      or [])

        # check the request or session for enabled filters, or use default
        filters = [f[0] for f in available_filters if f[0] in req.args]
        if not filters and format != 'rss':
            filters = [f[0] for f in available_filters
                            if req.session.as_int('timeline.filter.' + f[0])]
        if not filters:
            filters = [f[0] for f in available_filters if len(f) == 2 or f[2]]

        # save the results of submitting the timeline form to the session
        if 'update' in req.args:
            for filter_ in available_filters:
                key = 'timeline.filter.%s' % filter_[0]
                if filter_[0] in req.args:
                    req.session[key] = '1'
                elif key in req.session:
                    del req.session[key]

        stop = fromdate
        start = to_datetime(stop.replace(tzinfo=None) -
                            timedelta(days=daysback + 1), req.tz)

        # create author include and exclude sets
        include = set()
        exclude = set()
        for match in self._authors_pattern.finditer(authors):
            name = (match.group(2) or match.group(3) or match.group(4)).lower()
            if match.group(1):
                exclude.add(name)
            else:
                include.add(name)

        # gather all events for the given period of time
        events = []
        for provider in self.event_providers:
            with component_guard(self.env, req, provider):
                for event in provider.get_timeline_events(req, start, stop,
                                                          filters) or []:
                    author = (event[2] or '').lower()
                    if ((not include or author in include) and
                        author not in exclude):
                        events.append(
                            self._event_data(req, provider, event, lastvisit))

        # prepare sorted global list
        events = sorted(events, key=lambda e: e['datetime'], reverse=True)
        if maxrows:
            events = events[:maxrows]

        data['events'] = events

        if format == 'rss':
            rss_context = web_context(req, absurls=True)
            rss_context.set_hints(wiki_flavor='html', shorten_lines=False)
            data['context'] = rss_context
            return 'timeline.rss', data, {'content_type': 'application/rss+xml'}
        else:
            req.session.set('timeline.daysback', daysback,
                            self.default_daysback)
            req.session.set('timeline.authors', authors, '')
            # store lastvisit
            if events and not revisit:
                lastviewed = to_utimestamp(events[0]['datetime'])
                req.session['timeline.lastvisit'] = max(lastvisit, lastviewed)
                req.session['timeline.nextlastvisit'] = lastvisit
            html_context = web_context(req)
            html_context.set_hints(wiki_flavor='oneliner',
                                   shorten_lines=self.abbreviated_messages)
            data['context'] = html_context

        add_stylesheet(req, 'common/css/timeline.css')
        rss_href = req.href.timeline([(f, 'on') for f in filters],
                                     daysback=90, max=50, authors=authors,
                                     format='rss')
        add_link(req, 'alternate', auth_link(req, rss_href), _('RSS Feed'),
                 'application/rss+xml', 'rss')
        Chrome(self.env).add_jquery_ui(req)

        for filter_ in available_filters:
            data['filters'].append({'name': filter_[0], 'label': filter_[1],
                                    'enabled': filter_[0] in filters})

        # Navigation to the previous/next period of 'daysback' days
        previous_start = fromdate.replace(tzinfo=None) - \
                         timedelta(days=daysback + 1)
        previous_start = format_date(previous_start, format='iso8601',
                                     tzinfo=req.tz)
        add_link(req, 'prev', req.href.timeline(from_=previous_start,
                                                authors=authors,
                                                daysback=daysback),
                 _("Previous Period"))
        if today - fromdate > timedelta(days=0):
            next_start = fromdate.replace(tzinfo=None) + \
                         timedelta(days=daysback + 1)
            next_start = format_date(to_datetime(next_start, req.tz),
                                     format='iso8601', tzinfo=req.tz)
            add_link(req, 'next', req.href.timeline(from_=next_start,
                                                    authors=authors,
                                                    daysback=daysback),
                     _("Next Period"))
        prevnext_nav(req, _("Previous Period"), _("Next Period"))

        return 'timeline.html', data
예제 #34
0
    def _do_save(self, req, db, version):
        version_name = req.args.get('name')
        version_project = req.args.get('project')
        old_version_project = self.__SmpModel.get_id_project_version(version.name)

        if version.exists:
            req.perm.require('MILESTONE_MODIFY')
        else:
            req.perm.require('MILESTONE_CREATE')

        old_name = version.name
        new_name = version_name
        
        version.description = req.args.get('description', '')

        time = req.args.get('time', '')
        if time:
            version.time = user_time(req, parse_date, time, hint='datetime')
        else:
            version.time = None

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []
        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        # If the name has changed, check that the version doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        try:
            new_version = Version(self.env, new_name, db)
            if new_version.name == old_name:
                pass        # Creation or no name change
            elif new_version.name:
                warn(_('Version "%(name)s" already exists, please '
                       'choose another name.', name=new_version.name))
            else:
                warn(_('You must provide a name for the version.'))
        except:
            version.name = new_name

        if warnings:
            return self._render_editor(req, db, version)
        
        # -- actually save changes

        if version.exists:
            version.update()

            if old_name != version.name:
                self.__SmpModel.rename_version_project(old_name, version.name)
               
            if not version_project:
                self.__SmpModel.delete_version_project(version.name)
            elif not old_version_project:
                self.__SmpModel.insert_version_project(version.name, version_project)    
            else:
                self.__SmpModel.update_version_project(version.name, version_project)    
        else:
            version.insert()
            if version_project:
                self.__SmpModel.insert_version_project(version.name, version_project)    


        add_notice(req, _('Your changes have been saved.'))
        req.redirect(req.href.version(version.name))
예제 #35
0
    def _do_save(self, req, version):
        resource = Resource('version', version.name)
        if version.exists:
            req.perm(resource).require('VERSION_MODIFY')
        else:
            req.perm(resource).require('VERSION_CREATE')

        old_name = version.name
        new_name = req.args.get('name')

        version.name = new_name
        version.description = req.args.get('description', '')

        time = req.args.get('time', '')

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []

        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        if new_name:
            if new_name != old_name:
                # check that the version doesn't already exists
                # FIXME: the whole .exists business needs to be clarified
                #        (#4130) and should behave like a WikiPage does in
                #        this respect.
                try:
                    Version(self.env, new_name)
                    warn(
                        _(
                            'Version "%(name)s" already exists, please '
                            'choose another name',
                            name=new_name))
                except ResourceNotFound:
                    pass
        else:
            warn(_('You must provide a name for the version.'))

        # -- check completed date
        if 'released' in req.args:
            time = user_time(req, parse_date, time, hint='datetime') \
                   if time else None
            if time and time > datetime.now(utc):
                warn(_("Release date may not be in the future"))
        else:
            time = None
        version.time = time

        if warnings:
            return self._render_editor(req, version)

        # -- actually save changes
        with self.env.db_transaction as db:
            if version.exists:
                if version.name != version._old_name:
                    # Update tickets
                    db(
                        """
                        UPDATE milestone_version SET version=%s WHERE version=%s
                        """, (version.name, version._old_name))
                version.update()
            else:
                version.insert()

        req.redirect(req.href.version(version.name))
예제 #36
0
파일: pdf.py 프로젝트: nyuhuhuu/trachacks
 def _format_datetime(t, req):
     return user_time(req, format_datetime, t)
예제 #37
0
파일: roadmap.py 프로젝트: exocad/exotrac
    def _do_save(self, req, milestone):
        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_MODIFY')
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')

        old_name = milestone.name
        new_name = req.args.get('name')

        milestone.description = req.args.get('description', '')

        if 'due' in req.args:
            due = req.args.get('duedate', '')
            milestone.due = user_time(req, parse_date, due, hint='datetime') \
                            if due else None
        else:
            milestone.due = None

        completed = req.args.get('completeddate', '')
        retarget_to = req.args.get('target') or None

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []
        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        # If the name has changed, check that the milestone doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        try:
            new_milestone = Milestone(self.env, new_name)
            if new_milestone.name == old_name:
                pass        # Creation or no name change
            elif new_milestone.name:
                warn(_('Milestone "%(name)s" already exists, please '
                       'choose another name.', name=new_milestone.name))
            else:
                warn(_('You must provide a name for the milestone.'))
        except ResourceNotFound:
            milestone.name = new_name

        # -- check completed date
        if 'completed' in req.args:
            completed = user_time(req, parse_date, completed,
                                  hint='datetime') if completed else None
            if completed and completed > datetime.now(utc):
                warn(_('Completion date may not be in the future'))
        else:
            completed = None
        milestone.completed = completed

        if warnings:
            return self._render_editor(req, milestone)

        # -- actually save changes
        if milestone.exists:
            milestone.update(author=req.authname)
            if completed and 'retarget' in req.args:
                comment = req.args.get('comment', '')
                retargeted_tickets = \
                    milestone.move_tickets(retarget_to, req.authname,
                                           comment, exclude_closed=True)
                add_notice(req, _('The open tickets associated with '
                                  'milestone "%(name)s" have been retargeted '
                                  'to milestone "%(retarget)s".',
                                  name=milestone.name, retarget=retarget_to))
                new_values = {'milestone': retarget_to}
                comment = comment or \
                          _("Open tickets retargeted after milestone closed")
                tn = BatchTicketNotifyEmail(self.env)
                try:
                    tn.notify(retargeted_tickets, new_values, comment, None,
                              req.authname)
                except Exception, e:
                    self.log.error("Failure sending notification on ticket "
                                   "batch change: %s",
                                   exception_to_unicode(e))
                    add_warning(req, tag_("The changes have been saved, but "
                                          "an error occurred while sending "
                                          "notifications: %(message)s",
                                          message=to_unicode(e)))
예제 #38
0
파일: admin.py 프로젝트: dammina/bloodhound
    def _render_admin_panel(self, req, cat, page, milestone):
        perm = req.perm('admin', 'ticket/' + self._type)
        # Detail view?
        if milestone:
            mil = model.Milestone(self.env, milestone)
            if req.method == 'POST':
                if req.args.get('save'):
                    perm.require('MILESTONE_MODIFY')
                    mil.name = name = req.args.get('name')
                    mil.due = mil.completed = None
                    due = req.args.get('duedate', '')
                    if due:
                        mil.due = user_time(req,
                                            parse_date,
                                            due,
                                            hint='datetime')
                    if req.args.get('completed', False):
                        completed = req.args.get('completeddate', '')
                        mil.completed = user_time(req,
                                                  parse_date,
                                                  completed,
                                                  hint='datetime')
                        if mil.completed > datetime_now(utc):
                            raise TracError(
                                _('Completion date may not be in '
                                  'the future'), _('Invalid Completion Date'))
                    mil.description = req.args.get('description', '')
                    try:
                        mil.update(author=req.authname)
                    except self.env.db_exc.IntegrityError:
                        raise TracError(
                            _('Milestone "%(name)s" already '
                              'exists.',
                              name=name))
                    add_notice(req, _('Your changes have been saved.'))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            Chrome(self.env).add_wiki_toolbars(req)
            data = {'view': 'detail', 'milestone': mil}

        else:
            default = self.config.get('ticket', 'default_milestone')
            if req.method == 'POST':
                # Add Milestone
                if req.args.get('add') and req.args.get('name'):
                    perm.require('MILESTONE_CREATE')
                    name = req.args.get('name')
                    try:
                        mil = model.Milestone(self.env, name=name)
                    except ResourceNotFound:
                        mil = model.Milestone(self.env)
                        mil.name = name
                        if req.args.get('duedate'):
                            mil.due = user_time(req,
                                                parse_date,
                                                req.args.get('duedate'),
                                                hint='datetime')
                        mil.insert()
                        add_notice(
                            req,
                            _('The milestone "%(name)s" has been '
                              'added.',
                              name=name))
                        req.redirect(req.href.admin(cat, page))
                    else:
                        if mil.name is None:
                            raise TracError(_('Invalid milestone name.'))
                        raise TracError(
                            _('Milestone "%(name)s" already '
                              'exists.',
                              name=name))

                # Remove milestone
                elif req.args.get('remove'):
                    perm.require('MILESTONE_DELETE')
                    sel = req.args.get('sel')
                    if not sel:
                        raise TracError(_('No milestone selected'))
                    if not isinstance(sel, list):
                        sel = [sel]
                    with self.env.db_transaction:
                        for name in sel:
                            milestone = model.Milestone(self.env, name)
                            milestone.move_tickets(None, req.authname,
                                                   "Milestone deleted")
                            milestone.delete()
                    add_notice(
                        req, _("The selected milestones have been "
                               "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default milestone
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default milestone to %s", name)
                        self.config.set('ticket', 'default_milestone', name)
                        _save_config(self.config, req, self.log)
                        req.redirect(req.href.admin(cat, page))

            # Get ticket count
            milestones = [(milestone,
                           self.env.db_query(
                               """
                    SELECT COUNT(*) FROM ticket WHERE milestone=%s
                    """, (milestone.name, ))[0][0])
                          for milestone in model.Milestone.select(self.env)]

            data = {
                'view': 'list',
                'milestones': milestones,
                'default': default
            }

        Chrome(self.env).add_jquery_ui(req)

        data.update({
            'datetime_hint': get_datetime_format_hint(req.lc_time),
        })
        return 'admin_milestones.html', data
예제 #39
0
파일: admin.py 프로젝트: dammina/bloodhound
    def _render_admin_panel(self, req, cat, page, version):
        # Detail view?
        if version:
            ver = model.Version(self.env, version)
            if req.method == 'POST':
                if req.args.get('save'):
                    ver.name = name = req.args.get('name')
                    if req.args.get('time'):
                        ver.time = user_time(req,
                                             parse_date,
                                             req.args.get('time'),
                                             hint='datetime')
                    else:
                        ver.time = None  # unset
                    ver.description = req.args.get('description')
                    try:
                        ver.update()
                    except self.env.db_exc.IntegrityError:
                        raise TracError(
                            _('Version "%(name)s" already '
                              'exists.',
                              name=name))

                    add_notice(req, _('Your changes have been saved.'))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            Chrome(self.env).add_wiki_toolbars(req)
            data = {'view': 'detail', 'version': ver}

        else:
            default = self.config.get('ticket', 'default_version')
            if req.method == 'POST':
                # Add Version
                if req.args.get('add') and req.args.get('name'):
                    name = req.args.get('name')
                    try:
                        ver = model.Version(self.env, name=name)
                    except ResourceNotFound:
                        ver = model.Version(self.env)
                        ver.name = name
                        if req.args.get('time'):
                            ver.time = user_time(req,
                                                 parse_date,
                                                 req.args.get('time'),
                                                 hint='datetime')
                        ver.insert()
                        add_notice(
                            req,
                            _('The version "%(name)s" has been '
                              'added.',
                              name=name))
                        req.redirect(req.href.admin(cat, page))
                    else:
                        if ver.name is None:
                            raise TracError(_("Invalid version name."))
                        raise TracError(
                            _('Version "%(name)s" already '
                              'exists.',
                              name=name))

                # Remove versions
                elif req.args.get('remove'):
                    sel = req.args.get('sel')
                    if not sel:
                        raise TracError(_("No version selected"))
                    if not isinstance(sel, list):
                        sel = [sel]
                    with self.env.db_transaction:
                        for name in sel:
                            ver = model.Version(self.env, name)
                            ver.delete()
                    add_notice(
                        req, _("The selected versions have been "
                               "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default version
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default version to %s", name)
                        self.config.set('ticket', 'default_version', name)
                        _save_config(self.config, req, self.log)
                        req.redirect(req.href.admin(cat, page))

            data = {
                'view': 'list',
                'versions': list(model.Version.select(self.env)),
                'default': default
            }

        Chrome(self.env).add_jquery_ui(req)

        data.update({
            'datetime_hint': get_datetime_format_hint(req.lc_time),
        })
        return 'admin_versions.html', data
예제 #40
0
    def save_milestone(self, req, milestone):
        # Instead of raising one single error, check all the constraints
        # and let the user fix them by going back to edit mode and showing
        # the warnings
        warnings = []

        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        milestone.description = req.args.get('description', '')

        if 'due' in req.args:
            duedate = req.args.get('duedate')
            milestone.due = user_time(req, parse_date, duedate,
                                      hint='datetime') \
                            if duedate else None
        else:
            milestone.due = None

        # -- check completed date
        if 'completed' in req.args:
            completed = req.args.get('completeddate', '')
            completed = user_time(req, parse_date, completed,
                                  hint='datetime') if completed else None
            if completed and completed > datetime_now(utc):
                warn(_("Completion date may not be in the future"))
        else:
            completed = None
        milestone.completed = completed

        # -- check the name
        # If the name has changed, check that the milestone doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        new_name = req.args.get('name')
        try:
            new_milestone = Milestone(self.env, new_name)
        except ResourceNotFound:
            milestone.name = new_name
        else:
            if new_milestone.name != milestone.name:
                if new_milestone.name:
                    warn(
                        _(
                            'Milestone "%(name)s" already exists, please '
                            'choose another name.',
                            name=new_milestone.name))
                else:
                    warn(_("You must provide a name for the milestone."))

        if warnings:
            return False

        # -- actually save changes
        if milestone.exists:
            milestone.update(author=req.authname)
            if completed and 'retarget' in req.args:
                comment = req.args.get('comment', '')
                retarget_to = req.args.get('target') or None
                retargeted_tickets = \
                    milestone.move_tickets(retarget_to, req.authname,
                                           comment, exclude_closed=True)
                add_notice(
                    req,
                    _(
                        'The open tickets associated with '
                        'milestone "%(name)s" have been retargeted '
                        'to milestone "%(retarget)s".',
                        name=milestone.name,
                        retarget=retarget_to))
                new_values = {'milestone': retarget_to}
                comment = comment or \
                          _("Open tickets retargeted after milestone closed")
                event = BatchTicketChangeEvent(retargeted_tickets, None,
                                               req.authname, comment,
                                               new_values, None)
                try:
                    NotificationSystem(self.env).notify(event)
                except Exception as e:
                    self.log.error(
                        "Failure sending notification on ticket "
                        "batch change: %s", exception_to_unicode(e))
                    add_warning(
                        req,
                        tag_(
                            "The changes have been saved, but "
                            "an error occurred while sending "
                            "notifications: %(message)s",
                            message=to_unicode(e)))
            add_notice(req, _("Your changes have been saved."))
        else:
            milestone.insert()
            add_notice(
                req,
                _('The milestone "%(name)s" has been added.',
                  name=milestone.name))

        return True
예제 #41
0
    def _do_actions(self, context, actions):

        api = TrackerApi()

        time_interval = self.env.config.getint('tracker', 'time_interval', 10)
        time_separate = 1
        minutes_interval=0
        screenshotsWithHourse = []
        screenshotsWithMinutes = []
        template_hourse = []
        minute = 0
        min_hourse = 0
        max_hourse = 0
        allScreenshots=[]

        for action in actions:
            if action == 'view':
                date = datetime.datetime.now(context.req.tz)
                if 'date' in context.req.args:
                    date_from_calendar = context.req.args['date'].strip()
                    if date_from_calendar:
                        precisedate = user_time(context.req, parse_date, date_from_calendar)
                        date = precisedate.astimezone(context.req.tz)
                to_date = to_datetime(datetime.datetime(date.year, date.month, date.day,
                                               23, 59, 59, 999999), context.req.tz)
                to_date_timestamp = to_timestamp(to_date)

                full_date = {
                    'from_date': to_date_timestamp - 86400,
                    'to_date'  : to_date_timestamp
                }

                context.req.data['fromdate'] = to_date
                context.req.data['username'] = context.req.args.get('username')

                screenshot_id = int(context.req.args.get('id') or 0)
                screenshots = api.get_screenshots(context, context.req.args.get('username'), full_date)

                context.req.data['id'] = screenshot_id

                for hourse in range(0, 24):
                    for screenshot in screenshots:
                        screenshot["hourse"] = datetime.datetime.fromtimestamp(screenshot["time"]).strftime('%H')
                        if (int(screenshot["hourse"]) == hourse):
                            if min_hourse == 0:
                                min_hourse = hourse
                            elif min_hourse > hourse:
                                min_hourse = hourse
                            if max_hourse < hourse:
                                max_hourse = hourse
                            screenshotsWithHourse.append({hourse:screenshot})

                while (minute <= 59):
                    for screenshotsAll in screenshotsWithHourse:

                        for index in screenshotsAll:

                            screenshotMinute = datetime.datetime.fromtimestamp(float(screenshotsAll[index]["time"])).strftime('%M')
                            if int(screenshotMinute) == minute:
                                screenshotHourse = datetime.datetime.fromtimestamp(screenshotsAll[index]["time"]).strftime('%H')
                                if int(screenshotHourse) not in template_hourse:
                                    template_hourse.append(int(screenshotHourse))
                                screenshotsAll[index]['hourse'] = int(screenshotHourse)
                                screenshotsAll[index]['minute'] = int(screenshotMinute)
                                if len(screenshotsWithMinutes)>0 and screenshotsWithMinutes[0]['minute']==screenshotsAll[index]['minute']:
                                    screenshotsWithMinutes.pop()
                                screenshotsWithMinutes.append(screenshotsAll[index])
                    minute += 10
                for hourse in template_hourse:
                    for screenshot in screenshotsWithMinutes:
                        if screenshot['hourse']==hourse:
                            while screenshot['minute']!=minutes_interval:
                                allScreenshots.append({"hourse":hourse,"screen":None,"minute":minutes_interval})
                                minutes_interval+=10
                            screenshot["screen"]=1
                            allScreenshots.append(screenshot)
                            minutes_interval+=10
                    while (minutes_interval!=60):
                        allScreenshots.append({"hourse":hourse,"screen":None,"minute":minutes_interval})
                        minutes_interval+=10
                    minutes_interval=0

                context.req.data['allScreenshots'] = allScreenshots
                context.req.data['template_hourse'] = range(int(min_hourse), int(max_hourse)+time_separate)
                context.req.data['time_interval'] = time_interval
                context.req.data['time_separate'] = time_separate
                context.req.data['template'] = 'user_worklog_view.html'
                add_stylesheet(context.req, 'trac/css/tracker.css')
                chrome = Chrome(self.env)
                chrome.add_jquery_ui(context.req)

                return 'screenshots', None

            if action == 'get-file':

                screenshot_id = int(context.req.args.get('id') or 0)
                format = context.req.args.get('format') or self.default_format

                screenshot = api.get_screenshot(context, screenshot_id)

                if format == 'html':
                    context.req.data['screenshot'] = screenshot
                    return 'screenshot', None
                else:
                    screenshot_path = screenshot[0]['path']
                    filename = self.path + '/' + screenshot_path

                    file = open(filename.encode('utf-8'), "r")
                    file_data = file.read(1000)
                    file.close()

                    mimeview = Mimeview(self.env)
                    mime_type = mimeview.get_mimetype(filename, file_data)
                    if not mime_type:
                        mime_type = 'application/octet-stream'
                    if 'charset=' not in mime_type:
                        charset = mimeview.get_charset(file_data, mime_type)
                        mime_type = mime_type + '; charset=' + charset

                    context.req.send_file(filename.encode('utf-8'), mime_type)
            elif action == 'get-users':

                context.req.data['users'] = api.get_users(context)
                context.req.data['template'] = 'user_list.html'
                context.req.data['client'] = {'download_href': 'jar-tracker/' + calculate_client_package_name()}
                return 'screenshots', None
            else:
                return 'screenshots', None
예제 #42
0
 def test_render_time_field_datetime(self):
     req = MockRequest(self.env, method='GET', path_info='/ticket/1')
     value = datetime(2015, 7, 8, 12, 34, 56, tzinfo=utc)
     expected = user_time(req, format_datetime, value)
     self._test_render_time_field('datetime', req, value, expected)
예제 #43
0
    def process_request(self, req):
        req.perm.assert_permission('TIMELINE_VIEW')

        format = req.args.get('format')
        maxrows = int(req.args.get('max', 50 if format == 'rss' else 0))
        lastvisit = int(req.session.get('timeline.lastvisit', '0'))

        # indication of new events is unchanged when form is updated by user
        revisit = any(a in req.args
                      for a in ['update', 'from', 'daysback', 'author'])
        if revisit:
            lastvisit = int(
                req.session.get('timeline.nextlastvisit', lastvisit))

        # Parse the from date and adjust the timestamp to the last second of
        # the day
        fromdate = today = datetime.now(req.tz)
        precisedate = precision = None
        if 'from' in req.args:
            # Acquire from date only from non-blank input
            reqfromdate = req.args['from'].strip()
            if reqfromdate:
                precisedate = user_time(req, parse_date, reqfromdate)
                fromdate = precisedate
            precision = req.args.get('precision', '')
            if precision.startswith('second'):
                precision = timedelta(seconds=1)
            elif precision.startswith('minute'):
                precision = timedelta(minutes=1)
            elif precision.startswith('hour'):
                precision = timedelta(hours=1)
            else:
                precision = None
        fromdate = fromdate.replace(hour=23,
                                    minute=59,
                                    second=59,
                                    microsecond=999999)

        daysback = as_int(req.args.get('daysback'),
                          90 if format == 'rss' else None)
        if daysback is None:
            daysback = as_int(req.session.get('timeline.daysback'), None)
        if daysback is None:
            daysback = self.default_daysback
        daysback = max(0, daysback)
        if self.max_daysback >= 0:
            daysback = min(self.max_daysback, daysback)

        authors = req.args.get('authors')
        if authors is None and format != 'rss':
            authors = req.session.get('timeline.authors')
        authors = (authors or '').strip()

        data = {
            'fromdate': fromdate,
            'daysback': daysback,
            'authors': authors,
            'today': user_time(req, format_date, today),
            'yesterday': user_time(req, format_date,
                                   today - timedelta(days=1)),
            'precisedate': precisedate,
            'precision': precision,
            'events': [],
            'filters': [],
            'abbreviated_messages': self.abbreviated_messages,
            'lastvisit': lastvisit
        }

        available_filters = []
        for event_provider in self.event_providers:
            available_filters += event_provider.get_timeline_filters(req) or []

        # check the request or session for enabled filters, or use default
        filters = [f[0] for f in available_filters if f[0] in req.args]
        if not filters and format != 'rss':
            filters = [
                f[0] for f in available_filters
                if req.session.get('timeline.filter.' + f[0]) == '1'
            ]
        if not filters:
            filters = [f[0] for f in available_filters if len(f) == 2 or f[2]]

        # save the results of submitting the timeline form to the session
        if 'update' in req.args:
            for filter in available_filters:
                key = 'timeline.filter.%s' % filter[0]
                if filter[0] in req.args:
                    req.session[key] = '1'
                elif key in req.session:
                    del req.session[key]

        stop = fromdate
        start = stop - timedelta(days=daysback + 1)

        # create author include and exclude sets
        include = set()
        exclude = set()
        for match in self._authors_pattern.finditer(authors):
            name = (match.group(2) or match.group(3) or match.group(4)).lower()
            if match.group(1):
                exclude.add(name)
            else:
                include.add(name)

        # gather all events for the given period of time
        events = []
        for provider in self.event_providers:
            try:
                for event in provider.get_timeline_events(
                        req, start, stop, filters) or []:
                    # Check for 0.10 events
                    author = (event[2 if len(event) < 6 else 4] or '').lower()
                    if (not include or author in include) \
                       and not author in exclude:
                        events.append(self._event_data(provider, event))
            except Exception, e:  # cope with a failure of that provider
                self._provider_failure(e, req, provider, filters,
                                       [f[0] for f in available_filters])
예제 #44
0
    def _do_save(self, req, milestone):
        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_MODIFY')
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')

        old_name = milestone.name
        new_name = req.args.get('name')

        milestone.description = req.args.get('description', '')

        if 'due' in req.args:
            due = req.args.get('duedate', '')
            milestone.due = user_time(req, parse_date, due, hint='datetime') \
                            if due else None
        else:
            milestone.due = None

        completed = req.args.get('completeddate', '')
        retarget_to = req.args.get('target')

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []

        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        # If the name has changed, check that the milestone doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        try:
            new_milestone = Milestone(self.env, new_name)
            if new_milestone.name == old_name:
                pass  # Creation or no name change
            elif new_milestone.name:
                warn(
                    _(
                        'Milestone "%(name)s" already exists, please '
                        'choose another name.',
                        name=new_milestone.name))
            else:
                warn(_('You must provide a name for the milestone.'))
        except ResourceNotFound:
            milestone.name = new_name

        # -- check completed date
        if 'completed' in req.args:
            completed = user_time(req, parse_date, completed,
                                  hint='datetime') if completed else None
            if completed and completed > datetime.now(utc):
                warn(_('Completion date may not be in the future'))
        else:
            completed = None
        milestone.completed = completed

        if warnings:
            return self._render_editor(req, milestone)

        # -- actually save changes
        if milestone.exists:
            milestone.update()
            # eventually retarget opened tickets associated with the milestone
            if 'retarget' in req.args and completed:
                self.env.db_transaction(
                    """
                    UPDATE ticket SET milestone=%s
                    WHERE milestone=%s and status != 'closed'
                    """, (retarget_to, old_name))
                self.log.info("Tickets associated with milestone %s "
                              "retargeted to %s" % (old_name, retarget_to))
        else:
            milestone.insert()

        add_notice(req, _("Your changes have been saved."))
        req.redirect(req.href.milestone(milestone.name))
예제 #45
0
파일: batch.py 프로젝트: pkdevbox/trac
 def _parse_field_value(self, req, field, value):
     if field['type'] == 'time':
         return user_time(req, parse_date, value)
     return value
예제 #46
0
파일: stats.py 프로젝트: CoRfr/testman4trac
    def process_request(self, req):
        testmanagersystem = TestManagerSystem(self.env)
        tc_statuses = testmanagersystem.get_tc_statuses_by_color()

        if 'testmanager' in self.config:
            self.default_days_back = self.config.getint('testmanager', 'default_days_back', TESTMANAGER_DEFAULT_DAYS_BACK)
            self.default_interval = self.config.getint('testmanager', 'default_interval', TESTMANAGER_DEFAULT_INTERVAL)
        
        req_content = req.args.get('content')
        testplan = None
        catpath = None
        testplan_contains_all = True
        
        self.env.log.debug("Test Stats - process_request: %s" % req_content)

        grab_testplan = req.args.get('testplan')
        if grab_testplan and not grab_testplan == "__all":
            testplan = grab_testplan.partition('|')[0]
            catpath = grab_testplan.partition('|')[2]
            
            tp = TestPlan(self.env, testplan, catpath)
            testplan_contains_all = tp['contains_all']

        today = datetime.today()
        today = today.replace(tzinfo = req.tz)+timedelta(2)
        # Stats start from two years back
        beginning = today - timedelta(720)        

        if (not req_content == None) and (req_content == "piechartdata"):
            num_successful = 0
            for tc_outcome in tc_statuses['green']:
                num_successful += self._get_num_tcs_by_status(beginning, today, tc_outcome, testplan, req)

            num_failed = 0
            for tc_outcome in tc_statuses['red']:
                num_failed += self._get_num_tcs_by_status(beginning, today, tc_outcome, testplan, req)

            num_to_be_tested = 0
            if testplan_contains_all:
                num_to_be_tested = self._get_num_testcases(beginning, today, catpath, req) - num_successful - num_failed
            else:
                for tc_outcome in tc_statuses['yellow']:
                    num_to_be_tested += self._get_num_tcs_by_status(beginning, today, tc_outcome, testplan, req)

            jsdstr = """
            [
                {"response": "%s", "count": %s},
                {"response": "%s", "count": %s},
                {"response": "%s", "count": %s}
            ]
            """ % (_("Successful"), num_successful, _("Failed"), num_failed, _("To be tested"), num_to_be_tested)
            
            jsdstr = jsdstr.strip()
            
            if isinstance(jsdstr, unicode): 
                jsdstr = jsdstr.encode('utf-8') 

            req.send_header("Content-Length", len(jsdstr))
            req.write(jsdstr)
            return
        
        
        if not None in [req.args.get('end_date'), req.args.get('start_date'), req.args.get('resolution')]:
            # form submit
            grab_at_date = req.args.get('end_date')
            grab_from_date = req.args.get('start_date')
            grab_resolution = req.args.get('resolution')

            self.env.log.debug("Start date: %s", grab_from_date)
            self.env.log.debug("End date: %s", grab_at_date)

            # validate inputs
            if None in [grab_at_date, grab_from_date]:
                raise TracError('Please specify a valid range.')

            if None in [grab_resolution]:
                raise TracError('Please specify the graph interval.')
            
            if 0 in [len(grab_at_date), len(grab_from_date), len(grab_resolution)]:
                raise TracError('Please ensure that all fields have been filled in.')

            if not grab_resolution.isdigit():
                raise TracError('The graph interval field must be an integer, days.')

            if compatibility:
                at_date = parse_date(grab_at_date, req.tz)+timedelta(2)
                from_date = parse_date(grab_from_date, req.tz)
            else:
                at_date = user_time(req, parse_date, grab_at_date, hint='date')
                from_date = user_time(req, parse_date, grab_from_date, hint='date')

            graph_res = int(grab_resolution)

        else:
            # default data
            todays_date = datetime.today()
            at_date = todays_date #+ timedelta(1) # datetime.combine(todays_date,time(23,59,59,0,req.tz))
            at_date = at_date.replace(tzinfo = req.tz)+timedelta(2)
            from_date = at_date - timedelta(self.default_days_back)
            graph_res = self.default_interval
            
        count = []

        # Calculate 0th point 
        last_date = from_date - timedelta(graph_res)

        # Calculate remaining points
        for cur_date in daterange(from_date, at_date, graph_res):
            datestr = format_date(cur_date) 
            if graph_res != 1:
                datestr = "%s thru %s" % (format_date(last_date), datestr) 
            
            if (not req_content == None) and (req_content == "ticketchartdata"):
                num_total = self._get_num_tickets_total(beginning, cur_date, testplan, req)
                num_closed = self._get_num_tickets_by_status(beginning, cur_date, 'closed', testplan, req)
                num_active = num_total - num_closed
                
                count.append( {'from_date': format_date(last_date),
                             'to_date': datestr,
                             'date'  : datestr,
                             'active_tickets'    : num_active,
                             'closed_tickets': num_closed,
                             'tot_tickets' : num_total} )
                
            else:
                # Handling custom test case outcomes here
                num_new = self._get_num_testcases(last_date, cur_date, catpath, req)
                
                num_successful = 0
                for tc_outcome in tc_statuses['green']:
                    num_successful += self._get_num_tcs_by_status(last_date, cur_date, tc_outcome, testplan, req)

                num_failed = 0
                for tc_outcome in tc_statuses['red']:
                    num_failed += self._get_num_tcs_by_status(last_date, cur_date, tc_outcome, testplan, req)
                
                num_all_successful = 0
                for tc_outcome in tc_statuses['green']:
                    num_all_successful += self._get_num_tcs_by_status(from_date, cur_date, tc_outcome, testplan, req)

                num_all_failed = 0
                for tc_outcome in tc_statuses['red']:
                    num_all_failed += self._get_num_tcs_by_status(from_date, cur_date, tc_outcome, testplan, req)

                num_all = 0
                num_all_untested = 0
                if testplan_contains_all:
                    num_all = self._get_num_testcases(None, cur_date, catpath, req)
                    num_all_untested = num_all - num_all_successful - num_all_failed
                else:
                    for tc_outcome in tc_statuses['yellow']:
                        num_all_untested += self._get_num_tcs_by_status(from_date, cur_date, tc_outcome, testplan, req)
                    num_all = num_all_untested + num_all_successful + num_all_failed


                count.append( {'from_date': format_date(last_date),
                             'to_date': datestr,
                             'date'  : datestr,
                             'new_tcs'    : num_new,
                             'successful': num_successful,
                             'failed': num_failed,
                             'all_tcs'    : num_all,
                             'all_successful': num_all_successful,
                             'all_untested': num_all_untested,
                             'all_failed': num_all_failed })
                             
                             
            last_date = cur_date

        # if chartdata is requested, raw text is returned rather than data object
        # for templating
        if (not req_content == None) and (req_content == "chartdata"):
            jsdstr = '{"chartdata": [\n'

            for x in count:
                jsdstr += '{"date": "%s",' % x['date']
                jsdstr += ' "new_tcs": %s,' % x['new_tcs']
                jsdstr += ' "successful": %s,' % x['successful']
                jsdstr += ' "failed": %s,' % x['failed']
                jsdstr += ' "all_tcs": %s,' % x['all_tcs']
                jsdstr += ' "all_successful": %s,' % x['all_successful']
                jsdstr += ' "all_untested": %s,' % x['all_untested']
                jsdstr += ' "all_failed": %s},\n' % x['all_failed']
            jsdstr = jsdstr[:-2] +'\n]}'

            if isinstance(jsdstr, unicode): 
                jsdstr = jsdstr.encode('utf-8') 

            req.send_header("Content-Length", len(jsdstr))
            req.write(jsdstr)
            return
            
        elif (not req_content == None) and (req_content == "downloadcsv"):
            csvstr = "Date from;Date to;New Test Cases;Successful;Failed;Total Test Cases;Total Successful;Total Untested;Total Failed\r\n"
            for x in count:
                csvstr += '%s;' % x['from_date']
                csvstr += '%s;' % x['to_date']
                csvstr += '%s;' % x['new_tcs']
                csvstr += '%s;' % x['successful']
                csvstr += '%s;' % x['failed']
                csvstr += '%s;' % x['all_tcs']
                csvstr += '%s;' % x['all_successful']
                csvstr += '%s;' % x['all_untested']
                csvstr += '%s\r\n' % x['all_failed']
                
            if isinstance(csvstr, unicode): 
                csvstr = csvstr.encode('utf-8') 

            req.send_header("Content-Length", len(csvstr))
            req.send_header("Content-Disposition", "attachment;filename=Test_stats.csv")
            req.write(csvstr)
            return

        elif (not req_content == None) and (req_content == "ticketchartdata"):
            jsdstr = '{"ticketchartdata": [\n'
    
            for x in count:
                jsdstr += '{"date": "%s",' % x['date']
                jsdstr += ' "tot_tickets": %s,' % x['tot_tickets']
                jsdstr += ' "active_tickets": %s,' % x['active_tickets']
                jsdstr += ' "closed_tickets": %s},\n' % x['closed_tickets']
            jsdstr = jsdstr[:-2] +'\n]}'

            if isinstance(jsdstr, unicode): 
                jsdstr = jsdstr.encode('utf-8') 

            req.send_header("Content-Length", len(jsdstr))
            req.write(jsdstr)
            return
        
        else:
            # Normal rendering of first chart
            showall = req.args.get('show') == 'all'

            testplan_list = []
            for planid, catid, catpath, name, author, ts_str in testmanagersystem.list_all_testplans():
                testplan_list.append({'planid': planid, 'catpath': catpath, 'name': name})

            data = {}
            data['testcase_data'] = count
            data['resolution'] = str(graph_res)
            data['baseurl'] = req.base_url
            data['testplans'] = testplan_list
            data['ctestplan'] = testplan

            if compatibility:
                data['start_date'] = format_date(from_date)
                data['end_date'] = format_date(at_date)

                return 'testmanagerstats_compatible.html', data, None

            else:
                data['start_date'] = from_date
                data['end_date'] = at_date

                Chrome(self.env).add_jquery_ui(req)
                
                data.update({
                            'date_hint': get_date_format_hint(req.lc_time),
                        })
                        
                is_iso8601 = req.lc_time == 'iso8601'
                add_script_data(req, jquery_ui={
                    'month_names': get_month_names_jquery_ui(req),
                    'day_names': get_day_names_jquery_ui(req),
                    'date_format': get_date_format_jquery_ui(req.lc_time),
                    'time_format': get_time_format_jquery_ui(req.lc_time),
                    'ampm': not is_24_hours(req.lc_time),
                    'first_week_day': get_first_week_day_jquery_ui(req),
                    'timepicker_separator': 'T' if is_iso8601 else ' ',
                    'show_timezone': is_iso8601,
                    'timezone_list': get_timezone_list_jquery_ui() \
                                     if is_iso8601 else [],
                    'timezone_iso8601': is_iso8601,
                })
                    
            return 'testmanagerstats.html', data, None
예제 #47
0
    def process_request(self, req):
        """Process the request
        """
        base = self.get_mypage_base(req.authname)
        tzinfo = getattr(req, 'tz', None)
        now = datetime.now(tzinfo or localtz)
        today = format_date(now, 'iso8601', tzinfo)
        today_page_name = base + today
        today_page = WikiPage(self.env, today_page_name)
        if today_page.exists:
            req.redirect(req.href.wiki(today_page_name, action='edit'))

        # create page of the day for today
        if 'WIKI_CREATE' not in req.perm(today_page.resource):
            raise ResourceNotFound(_("Can't create the page of the day."))
        ws = WikiSystem(self.env)

        def get_page_text(pagename):
            if ws.has_page(pagename):
                page = WikiPage(self.env, pagename)
                if 'WIKI_VIEW' in req.perm(page.resource):
                    self.log.debug("get_page_text(%s) -> %s", pagename,
                                   page.text)
                    return page.text
            self.log.debug("get_page_text(%s) -> None", pagename)

        # retrieve page template
        template_name = 'PageTemplates/MyPage'
        mytemplate_name = '/'.join([template_name, req.authname])
        template_text = get_page_text(mytemplate_name)
        if template_text is None:
            template_text = get_page_text(template_name)

        text = last_page_text = last_page_quoted = None
        if template_text is not None:
            # retrieve previous "page of the day", if any
            all_mypages = self.get_all_mypages(base)
            last = bisect(all_mypages, today_page_name) - 1
            self.log.debug("Pos of today %s in %r is %d", today_page_name,
                           all_mypages, last)
            last_page_name = all_mypages[last] if last >= 0 else None
            last_page_link = ''
            if last_page_name:
                last_page_link = '[[%s]]' % last_page_name
                last_page_text = get_page_text(last_page_name)
                if last_page_text is not None:
                    last_page_quoted = '\n'.join(
                        ['> ' + line for line in last_page_text.splitlines()])

            today_user = user_time(req, format_date, now, tzinfo=tzinfo)
            author = req.session.get('name') or get_reporter_id(req)

            text = template_text \
                .replace(self.tokens['date'][0], today_user) \
                .replace(self.tokens['isodate'][0], today) \
                .replace(self.tokens['user'][0], req.authname) \
                .replace(self.tokens['author'][0], author) \
                .replace(self.tokens['lp_link'][0], last_page_link) \
                .replace(self.tokens['lp_name'][0], last_page_name or '') \
                .replace(self.tokens['lp_text'][0], last_page_text or '') \
                .replace(self.tokens['lp_quoted'][0], last_page_quoted or '')
        req.redirect(req.href.wiki(today_page_name, action='edit', text=text))
예제 #48
0
파일: admin.py 프로젝트: starworldx/trac
 def _get_user_time(cls, req):
     time = req.args.get('time')
     return user_time(req, parse_date, time, hint='datetime') \
            if time else None
예제 #49
0
    def process_request(self, req):
        req.perm.assert_permission('TIMELINE_VIEW')

        format = req.args.get('format')
        maxrows = int(req.args.get('max', 50 if format == 'rss' else 0))
        lastvisit = int(req.session.get('timeline.lastvisit', '0'))

        # indication of new events is unchanged when form is updated by user
        revisit = any(a in req.args for a in ['update', 'from', 'daysback',
                                              'author'])
        if revisit:
            lastvisit = int(req.session.get('timeline.nextlastvisit',
                                            lastvisit))

        # Parse the from date and adjust the timestamp to the last second of
        # the day
        fromdate = today = datetime.now(req.tz)
        yesterday = to_datetime(today.replace(tzinfo=None) - timedelta(days=1),
                                req.tz)
        precisedate = precision = None
        if 'from' in req.args:
            # Acquire from date only from non-blank input
            reqfromdate = req.args['from'].strip()
            if reqfromdate:
                precisedate = user_time(req, parse_date, reqfromdate)
                fromdate = precisedate.astimezone(req.tz)
            precision = req.args.get('precision', '')
            if precision.startswith('second'):
                precision = timedelta(seconds=1)
            elif precision.startswith('minute'):
                precision = timedelta(minutes=1)
            elif precision.startswith('hour'):
                precision = timedelta(hours=1)
            else:
                precision = None
        fromdate = to_datetime(datetime(fromdate.year, fromdate.month,
                                        fromdate.day, 23, 59, 59, 999999),
                               req.tz)

        daysback = as_int(req.args.get('daysback'),
                          90 if format == 'rss' else None)
        if daysback is None:
            daysback = as_int(req.session.get('timeline.daysback'), None)
        if daysback is None:
            daysback = self.default_daysback
        daysback = max(0, daysback)
        if self.max_daysback >= 0:
            daysback = min(self.max_daysback, daysback)

        authors = req.args.get('authors')
        if authors is None and format != 'rss':
            authors = req.session.get('timeline.authors')
        authors = (authors or '').strip()

        data = {'fromdate': fromdate, 'daysback': daysback,
                'authors': authors,
                'today': user_time(req, format_date, today),
                'yesterday': user_time(req, format_date, yesterday),
                'precisedate': precisedate, 'precision': precision,
                'events': [], 'filters': [],
                'abbreviated_messages': self.abbreviated_messages,
                'lastvisit': lastvisit}

        available_filters = []
        for event_provider in self.event_providers:
            available_filters += event_provider.get_timeline_filters(req) or []

        # check the request or session for enabled filters, or use default
        filters = [f[0] for f in available_filters if f[0] in req.args]
        if not filters and format != 'rss':
            filters = [f[0] for f in available_filters
                       if req.session.get('timeline.filter.' + f[0]) == '1']
        if not filters:
            filters = [f[0] for f in available_filters if len(f) == 2 or f[2]]

        # save the results of submitting the timeline form to the session
        if 'update' in req.args:
            for filter in available_filters:
                key = 'timeline.filter.%s' % filter[0]
                if filter[0] in req.args:
                    req.session[key] = '1'
                elif key in req.session:
                    del req.session[key]

        stop = fromdate
        start = to_datetime(stop.replace(tzinfo=None) - \
                                timedelta(days=daysback + 1),
                            req.tz)

        # create author include and exclude sets
        include = set()
        exclude = set()
        for match in self._authors_pattern.finditer(authors):
            name = (match.group(2) or match.group(3) or match.group(4)).lower()
            if match.group(1):
                exclude.add(name)
            else:
                include.add(name)

        # gather all events for the given period of time
        events = []
        for provider in self.event_providers:
            try:
                for event in provider.get_timeline_events(req, start, stop,
                                                          filters) or []:
                    # Check for 0.10 events
                    author = (event[2 if len(event) < 6 else 4] or '').lower()
                    if (not include or author in include) \
                       and not author in exclude:
                        events.append(self._event_data(provider, event))
            except Exception, e: # cope with a failure of that provider
                self._provider_failure(e, req, provider, filters,
                                       [f[0] for f in available_filters])
예제 #50
0
    def _do_save(self, req, milestone):
        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_MODIFY')
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')

        old_name = milestone.name
        new_name = req.args.get('name')

        milestone.description = req.args.get('description', '')

        if 'due' in req.args:
            due = req.args.get('duedate', '')
            milestone.due = user_time(req, parse_date, due, hint='datetime') \
                            if due else None
        else:
            milestone.due = None

        completed = req.args.get('completeddate', '')
        retarget_to = req.args.get('target')

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []
        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        # If the name has changed, check that the milestone doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        try:
            new_milestone = Milestone(self.env, new_name)
            if new_milestone.name == old_name:
                pass        # Creation or no name change
            elif new_milestone.name:
                warn(_('Milestone "%(name)s" already exists, please '
                       'choose another name.', name=new_milestone.name))
            else:
                warn(_('You must provide a name for the milestone.'))
        except ResourceNotFound:
            milestone.name = new_name

        # -- check completed date
        if 'completed' in req.args:
            completed = user_time(req, parse_date, completed,
                                  hint='datetime') if completed else None
            if completed and completed > datetime.now(utc):
                warn(_('Completion date may not be in the future'))
        else:
            completed = None
        milestone.completed = completed

        if warnings:
            return self._render_editor(req, milestone)

        # -- actually save changes
        if milestone.exists:
            milestone.update()
            # eventually retarget opened tickets associated with the milestone
            if 'retarget' in req.args and completed:
                self.env.db_transaction("""
                    UPDATE ticket SET milestone=%s
                    WHERE milestone=%s and status != 'closed'
                    """, (retarget_to, old_name))
                self.log.info("Tickets associated with milestone %s "
                              "retargeted to %s" % (old_name, retarget_to))
        else:
            milestone.insert()

        add_notice(req, _("Your changes have been saved."))
        req.redirect(req.href.milestone(milestone.name))
예제 #51
0
    def _render_admin_panel(self, req, cat, page, milestone):
        req.perm.require('MILESTONE_VIEW')

        # Detail view?
        if milestone:
            mil = model.Milestone(self.env, milestone)
            if req.method == 'POST':
                if req.args.get('save'):
                    req.perm.require('MILESTONE_MODIFY')
                    mil.name = name = req.args.get('name')
                    mil.due = mil.completed = None
                    due = req.args.get('duedate', '')
                    if due:
                        mil.due = user_time(req, parse_date, due,
                                            hint='datetime')
                    if req.args.get('completed', False):
                        completed = req.args.get('completeddate', '')
                        mil.completed = user_time(req, parse_date, completed,
                                                  hint='datetime')
                        if mil.completed > datetime.now(utc):
                            raise TracError(_('Completion date may not be in '
                                              'the future'),
                                            _('Invalid Completion Date'))
                    mil.description = req.args.get('description', '')
                    try:
                        mil.update()
                    except self.env.db_exc.IntegrityError:
                        raise TracError(_('The milestone "%(name)s" already '
                                          'exists.', name=name))
                    add_notice(req, _('Your changes have been saved.'))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            Chrome(self.env).add_wiki_toolbars(req)
            data = {'view': 'detail', 'milestone': mil}

        else:
            default = self.config.get('ticket', 'default_milestone')
            if req.method == 'POST':
                # Add Milestone
                if req.args.get('add') and req.args.get('name'):
                    req.perm.require('MILESTONE_CREATE')
                    name = req.args.get('name')
                    try:
                        mil = model.Milestone(self.env, name=name)
                    except ResourceNotFound:
                        mil = model.Milestone(self.env)
                        mil.name = name
                        if req.args.get('duedate'):
                            mil.due = user_time(req, parse_date,
                                                req.args.get('duedate'),
                                                hint='datetime')
                        mil.insert()
                        add_notice(req, _('The milestone "%(name)s" has been '
                                          'added.', name=name))
                        req.redirect(req.href.admin(cat, page))
                    else:
                        if mil.name is None:
                            raise TracError(_('Invalid milestone name.'))
                        raise TracError(_("Milestone %(name)s already exists.",
                                          name=name))

                # Remove milestone
                elif req.args.get('remove'):
                    req.perm.require('MILESTONE_DELETE')
                    sel = req.args.get('sel')
                    if not sel:
                        raise TracError(_('No milestone selected'))
                    if not isinstance(sel, list):
                        sel = [sel]
                    with self.env.db_transaction:
                        for name in sel:
                            mil = model.Milestone(self.env, name)
                            mil.delete(author=req.authname)
                    add_notice(req, _("The selected milestones have been "
                                      "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default milestone
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default milestone to %s", name)
                        self.config.set('ticket', 'default_milestone', name)
                        _save_config(self.config, req, self.log)
                        req.redirect(req.href.admin(cat, page))

            # Get ticket count
            milestones = [
                (milestone, self.env.db_query("""
                    SELECT COUNT(*) FROM ticket WHERE milestone=%s
                    """, (milestone.name,))[0][0])
                for milestone in model.Milestone.select(self.env)]

            data = {'view': 'list',
                    'milestones': milestones,
                    'default': default}

        Chrome(self.env).add_jquery_ui(req)

        data.update({
            'datetime_hint': get_datetime_format_hint(req.lc_time),
        })
        return 'admin_milestones.html', data
예제 #52
0
    def _render_admin_panel(self, req, cat, page, version):
        # Detail view?
        if version:
            ver = model.Version(self.env, version)
            if req.method == 'POST':
                if req.args.get('save'):
                    ver.name = req.args.get('name')
                    if req.args.get('time'):
                        ver.time = user_time(req, parse_date,
                                             req.args.get('time'),
                                             hint='datetime')
                    else:
                        ver.time = None  # unset
                    ver.description = req.args.get('description')
                    ver.update()
                    add_notice(req, _("Your changes have been saved."))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data = {'view': 'detail', 'version': ver}

        else:
            default = self.config.get('ticket', 'default_version')
            if req.method == 'POST':
                # Add Version
                if req.args.get('add') and req.args.get('name'):
                    ver = model.Version(self.env)
                    ver.name = req.args.get('name')
                    if req.args.get('time'):
                        ver.time = user_time(req, parse_date,
                                             req.args.get('time'),
                                             hint='datetime')
                    ver.insert()
                    add_notice(req, _('The version "%(name)s" has been '
                                      'added.', name=ver.name))
                    req.redirect(req.href.admin(cat, page))

                # Remove versions
                elif req.args.get('remove'):
                    sel = req.args.getlist('sel')
                    if not sel:
                        raise TracError(_("No version selected"))
                    with self.env.db_transaction:
                        for name in sel:
                            model.Version(self.env, name).delete()
                            if name == default:
                                self.config.set('ticket',
                                                'default_version', '')
                                self._save_config(req)
                    add_notice(req, _("The selected versions have been "
                                      "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default version
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default version to %s", name)
                        self.config.set('ticket', 'default_version', name)
                        self._save_config(req)
                        req.redirect(req.href.admin(cat, page))

                # Clear default version
                elif req.args.get('clear'):
                    self.log.info("Clearing default version")
                    self.config.set('ticket', 'default_version', '')
                    self._save_config(req)
                    req.redirect(req.href.admin(cat, page))

            data = {'view': 'list',
                    'versions': list(model.Version.select(self.env)),
                    'default': default}

        Chrome(self.env).add_jquery_ui(req)
        data.update({'datetime_hint': get_datetime_format_hint(req.lc_time)})

        return 'admin_versions.html', data
예제 #53
0
    def _do_actions(self, context, actions):

        api = TrackerApi()

        time_interval = self.env.config.getint('tracker', 'time_interval', 10)
        time_separate = 1
        minutes_interval = 0
        screenshotsWithHourse = []
        screenshotsWithMinutes = []
        template_hourse = []
        minute = 0
        min_hourse = 0
        max_hourse = 0
        allScreenshots = []

        for action in actions:
            if action == 'view':
                date = datetime.datetime.now(context.req.tz)
                if 'date' in context.req.args:
                    date_from_calendar = context.req.args['date'].strip()
                    if date_from_calendar:
                        precisedate = user_time(context.req, parse_date,
                                                date_from_calendar)
                        date = precisedate.astimezone(context.req.tz)
                to_date = to_datetime(
                    datetime.datetime(date.year, date.month, date.day, 23, 59,
                                      59, 999999), context.req.tz)
                to_date_timestamp = to_timestamp(to_date)

                full_date = {
                    'from_date': to_date_timestamp - 86400,
                    'to_date': to_date_timestamp
                }

                context.req.data['fromdate'] = to_date
                context.req.data['username'] = context.req.args.get('username')

                screenshot_id = int(context.req.args.get('id') or 0)
                screenshots = api.get_screenshots(
                    context, context.req.args.get('username'), full_date)

                context.req.data['id'] = screenshot_id

                for hourse in range(0, 24):
                    for screenshot in screenshots:
                        screenshot["hourse"] = datetime.datetime.fromtimestamp(
                            screenshot["time"]).strftime('%H')
                        if (int(screenshot["hourse"]) == hourse):
                            if min_hourse == 0:
                                min_hourse = hourse
                            elif min_hourse > hourse:
                                min_hourse = hourse
                            if max_hourse < hourse:
                                max_hourse = hourse
                            screenshotsWithHourse.append({hourse: screenshot})

                while (minute <= 59):
                    for screenshotsAll in screenshotsWithHourse:

                        for index in screenshotsAll:

                            screenshotMinute = datetime.datetime.fromtimestamp(
                                float(screenshotsAll[index]["time"])).strftime(
                                    '%M')
                            if int(screenshotMinute) == minute:
                                screenshotHourse = datetime.datetime.fromtimestamp(
                                    screenshotsAll[index]["time"]).strftime(
                                        '%H')
                                if int(screenshotHourse
                                       ) not in template_hourse:
                                    template_hourse.append(
                                        int(screenshotHourse))
                                screenshotsAll[index]['hourse'] = int(
                                    screenshotHourse)
                                screenshotsAll[index]['minute'] = int(
                                    screenshotMinute)
                                if len(screenshotsWithMinutes
                                       ) > 0 and screenshotsWithMinutes[0][
                                           'minute'] == screenshotsAll[index][
                                               'minute']:
                                    screenshotsWithMinutes.pop()
                                screenshotsWithMinutes.append(
                                    screenshotsAll[index])
                    minute += 10
                for hourse in template_hourse:
                    for screenshot in screenshotsWithMinutes:
                        if screenshot['hourse'] == hourse:
                            while screenshot['minute'] != minutes_interval:
                                allScreenshots.append({
                                    "hourse":
                                    hourse,
                                    "screen":
                                    None,
                                    "minute":
                                    minutes_interval
                                })
                                minutes_interval += 10
                            screenshot["screen"] = 1
                            allScreenshots.append(screenshot)
                            minutes_interval += 10
                    while (minutes_interval != 60):
                        allScreenshots.append({
                            "hourse": hourse,
                            "screen": None,
                            "minute": minutes_interval
                        })
                        minutes_interval += 10
                    minutes_interval = 0

                context.req.data['allScreenshots'] = allScreenshots
                context.req.data['template_hourse'] = range(
                    int(min_hourse),
                    int(max_hourse) + time_separate)
                context.req.data['time_interval'] = time_interval
                context.req.data['time_separate'] = time_separate
                context.req.data['template'] = 'user_worklog_view.html'
                add_stylesheet(context.req, 'trac/css/tracker.css')
                chrome = Chrome(self.env)
                chrome.add_jquery_ui(context.req)

                return 'screenshots', None

            if action == 'get-file':

                screenshot_id = int(context.req.args.get('id') or 0)
                format = context.req.args.get('format') or self.default_format

                screenshot = api.get_screenshot(context, screenshot_id)

                if format == 'html':
                    context.req.data['screenshot'] = screenshot
                    return 'screenshot', None
                else:
                    screenshot_path = screenshot[0]['path']
                    filename = self.path + '/' + screenshot_path

                    file = open(filename.encode('utf-8'), "r")
                    file_data = file.read(1000)
                    file.close()

                    mimeview = Mimeview(self.env)
                    mime_type = mimeview.get_mimetype(filename, file_data)
                    if not mime_type:
                        mime_type = 'application/octet-stream'
                    if 'charset=' not in mime_type:
                        charset = mimeview.get_charset(file_data, mime_type)
                        mime_type = mime_type + '; charset=' + charset

                    context.req.send_file(filename.encode('utf-8'), mime_type)
            elif action == 'get-users':

                context.req.data['users'] = api.get_users(context)
                context.req.data['template'] = 'user_list.html'
                context.req.data['client'] = {
                    'download_href':
                    'jar-tracker/' + calculate_client_package_name()
                }
                return 'screenshots', None
            else:
                return 'screenshots', None
예제 #54
0
    def _render_admin_panel(self, req, cat, page, version):
        # Detail view?
        if version:
            ver = model.Version(self.env, version)
            if req.method == 'POST':
                if req.args.get('save'):
                    ver.name = name = req.args.get('name')
                    if req.args.get('time'):
                        ver.time = user_time(req, parse_date,
                                             req.args.get('time'),
                                             hint='datetime')
                    else:
                        ver.time = None # unset
                    ver.description = req.args.get('description')
                    try:
                        ver.update()
                    except self.env.db_exc.IntegrityError:
                        raise TracError(_('The version "%(name)s" already '
                                          'exists.', name=name))

                    add_notice(req, _('Your changes have been saved.'))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            Chrome(self.env).add_wiki_toolbars(req)
            data = {'view': 'detail', 'version': ver}

        else:
            default = self.config.get('ticket', 'default_version')
            if req.method == 'POST':
                # Add Version
                if req.args.get('add') and req.args.get('name'):
                    name = req.args.get('name')
                    try:
                        ver = model.Version(self.env, name=name)
                    except ResourceNotFound:
                        ver = model.Version(self.env)
                        ver.name = name
                        if req.args.get('time'):
                            ver.time = user_time(req, parse_date,
                                                 req.args.get('time'),
                                                 hint='datetime')
                        ver.insert()
                        add_notice(req, _('The version "%(name)s" has been '
                                          'added.', name=name))
                        req.redirect(req.href.admin(cat, page))
                    else:
                        if ver.name is None:
                            raise TracError(_("Invalid version name."))
                        raise TracError(_("Version %(name)s already exists.",
                                          name=name))

                # Remove versions
                elif req.args.get('remove'):
                    sel = req.args.get('sel')
                    if not sel:
                        raise TracError(_("No version selected"))
                    if not isinstance(sel, list):
                        sel = [sel]
                    with self.env.db_transaction:
                        for name in sel:
                            ver = model.Version(self.env, name)
                            ver.delete()
                    add_notice(req, _("The selected versions have been "
                                      "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default version
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default version to %s", name)
                        self.config.set('ticket', 'default_version', name)
                        _save_config(self.config, req, self.log)
                        req.redirect(req.href.admin(cat, page))

            data = {'view': 'list',
                    'versions': model.Version.select(self.env),
                    'default': default}

        Chrome(self.env).add_jquery_ui(req)

        data.update({
            'datetime_hint': get_datetime_format_hint(req.lc_time),
        })
        return 'admin_versions.html', data
예제 #55
0
    def _do_save(self, req, db, version):
        version_name = req.args.get('name')
        version_project = req.args.get('project')
        old_version_project = self.__SmpModel.get_id_project_version(
            version.name)

        if version.exists:
            req.perm.require('MILESTONE_MODIFY')
        else:
            req.perm.require('MILESTONE_CREATE')

        old_name = version.name
        new_name = version_name

        version.description = req.args.get('description', '')

        time = req.args.get('time', '')
        if time:
            version.time = user_time(req, parse_date, time, hint='datetime')
        else:
            version.time = None

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []

        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        # If the name has changed, check that the version doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        try:
            new_version = Version(self.env, new_name, db)
            if new_version.name == old_name:
                pass  # Creation or no name change
            elif new_version.name:
                warn(
                    _(
                        'Version "%(name)s" already exists, please '
                        'choose another name.',
                        name=new_version.name))
            else:
                warn(_('You must provide a name for the version.'))
        except:
            version.name = new_name

        if warnings:
            return self._render_editor(req, db, version)

        # -- actually save changes

        if version.exists:
            version.update()

            if old_name != version.name:
                self.__SmpModel.rename_version_project(old_name, version.name)

            if not version_project:
                self.__SmpModel.delete_version_project(version.name)
            elif not old_version_project:
                self.__SmpModel.insert_version_project(version.name,
                                                       version_project)
            else:
                self.__SmpModel.update_version_project(version.name,
                                                       version_project)
        else:
            version.insert()
            if version_project:
                self.__SmpModel.insert_version_project(version.name,
                                                       version_project)

        add_notice(req, _('Your changes have been saved.'))
        req.redirect(req.href.version(version.name))