Exemple #1
0
 def _get_help_href(self, req):
     if not self.help_opt:
         return None
     link = resource_id = None
     if self.help_opt.startswith('/'):
         # Assume valid URL to arbitrary resource inside
         #   of the current Trac environment.
         link = req.href(self.help_opt)
     if not link and ':' in self.help_opt:
         realm, resource_id = self.help_opt.split(':', 1)
         # Validate realm-like prefix against resource realm list,
         #   but exclude 'wiki' to allow deferred page creation.
         rsys = ResourceSystem(self.env)
         if realm in set(rsys.get_known_realms()) - set('wiki'):
             mgr = rsys.get_resource_manager(realm)
             # Handle optional IResourceManager method gracefully.
             try:
                 if mgr.resource_exists(Resource(realm, resource_id)):
                     link = mgr.get_resource_url(resource_id, req.href)
             except AttributeError:
                 # Assume generic resource URL build rule.
                 link = req.href(realm, resource_id)
     if not link:
         if not resource_id:
             # Assume wiki page name for backwards-compatibility.
             resource_id = self.help_opt
         if '#' in resource_id:
             path, anchor = resource_id.split('#', 1)
             anchor = unicode_quote_plus(anchor, safe="?!~*'()")
             link = '#'.join((req.href.wiki(path), anchor))
         else:
             link = req.href.wiki(resource_id)
     return link
def make_trac_environment_with_plugin():
    env = EnvironmentStub(enable=["movie.*", MovieMacro, MoviePreviewRenderer])
    resource_system = ResourceSystem(env)
    resource_system._resource_managers_map = {
        'attachment': AttachmentModule(env),
    }
    movie_macro = MovieMacro(env)
    preview_renderer = MoviePreviewRenderer(env)
    return env, movie_macro, preview_renderer
Exemple #3
0
def resource_from_page(env, page):
    resource_realm = None
    resources = ResourceSystem(env)
    for realm in resources.get_known_realms():
        if page.startswith('/' + realm):
            resource_realm = realm
            break
    if resource_realm is not None:
        return (resource_realm, re.sub('/' + resource_realm, '',
                                       page).lstrip('/'))
    else:
        return page, None
Exemple #4
0
def resource_from_page(env, page):
    resource_realm = None
    resources = ResourceSystem(env)
    for realm in resources.get_known_realms():
        if page.startswith('/' + realm):
            resource_realm = realm
            break
    if resource_realm is not None:
        return (resource_realm,
                re.sub('/' + resource_realm, '', page).lstrip('/'))
    else:
        return page, None
Exemple #5
0
    def resource_exists(env, resource):
        """Checks for resource existence without actually instantiating a
        model.

        :return: `True` if the resource exists, `False` if it doesn't
        and `None` in case no conclusion could be made (i.e. when
        `IResourceManager.resource_exists` is not implemented).
        """
        manager = ResourceSystem(env).get_resource_manager(resource.realm)
        if manager and hasattr(manager, 'resource_exists'):
            return manager.resource_exists(resource)
        elif resource.id is None:
            return False
Exemple #6
0
    def delete(self, retarget_to=None, author=None, db=None):
        """Delete the milestone.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        with self.env.db_transaction as db:
            self.env.log.info("Deleting milestone %s", self.name)
            db("DELETE FROM milestone WHERE name=%s", (self.name, ))

            # Retarget/reset tickets associated with this milestone
            now = datetime.now(utc)
            tkt_ids = [
                int(row[0])
                for row in db("SELECT id FROM ticket WHERE milestone=%s", (
                    self.name, ))
            ]
            for tkt_id in tkt_ids:
                ticket = Ticket(self.env, tkt_id, db)
                ticket['milestone'] = retarget_to
                comment = "Milestone %s deleted" % self.name  # don't translate
                ticket.save_changes(author, comment, now)
            self._old['name'] = None
            del self.cache.milestones
            TicketSystem(self.env).reset_ticket_fields()

        for listener in TicketSystem(self.env).milestone_change_listeners:
            listener.milestone_deleted(self)
        ResourceSystem(self.env).resource_deleted(self)
Exemple #7
0
    def rename(self, new_name):
        """Rename wiki page in-place, keeping the history intact.
        Renaming a page this way will eventually leave dangling references
        to the old page - which litterally doesn't exist anymore.
        """
        assert self.exists, "Cannot rename non-existent page"

        if not validate_page_name(new_name):
            raise TracError(
                _("Invalid Wiki page name '%(name)s'", name=new_name))
        old_name = self.name

        with self.env.db_transaction as db:
            new_page = WikiPage(self.env, new_name)
            if new_page.exists:
                raise TracError(
                    _("Can't rename to existing %(name)s page.",
                      name=new_name))

            db("UPDATE wiki SET name=%s WHERE name=%s", (new_name, old_name))
            # Invalidate page name cache
            del WikiSystem(self.env).pages
            # Reparent attachments
            from trac.attachment import Attachment
            Attachment.reparent_all(self.env, 'wiki', old_name, 'wiki',
                                    new_name)

        self.name = new_name
        self.env.log.info('Renamed page %s to %s', old_name, new_name)

        for listener in WikiSystem(self.env).change_listeners:
            if hasattr(listener, 'wiki_page_renamed'):
                listener.wiki_page_renamed(self, old_name)

        ResourceSystem(self.env).resource_changed(self, dict(name=old_name))
Exemple #8
0
 def _get_env_for_resource(self, resource):
     if hasattr(resource, "neighborhood"):
         env = ResourceSystem(self.env).load_component_manager(
             resource.neighborhood)
     else:
         env = self.env
     return env
Exemple #9
0
    def update(self, db=None):
        """Update the component.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert self.exists, "Cannot update non-existent component"
        self.name = simplify_whitespace(self.name)
        if not self.name:
            raise TracError(_("Invalid component name."))

        old_name = self._old_name
        with self.env.db_transaction as db:
            self.env.log.info("Updating component '%s'", self.name)
            db(
                """UPDATE component SET name=%s,owner=%s, description=%s
                  WHERE name=%s
                  """,
                (self.name, self.owner, self.description, self._old_name))
            if self.name != self._old_name:
                # Update tickets
                db("UPDATE ticket SET component=%s WHERE component=%s",
                   (self.name, self._old_name))
                self._old_name = self.name
            TicketSystem(self.env).reset_ticket_fields()

        #todo:add support of old_values for owner and description fields
        old_values = dict()
        if self.name != old_name:
            old_values["name"] = old_name
        ResourceSystem(self.env).resource_changed(self, old_values)
Exemple #10
0
    def update(self, author=None):
        """Update the matching record in the database"""
        if self._old_data == self._data:
            return
        if not self._exists:
            raise TracError('%(object_name)s does not exist' % self._meta)
        for key in self._meta['no_change_fields']:
            if self._data[key] != self._old_data[key]:
                raise TracError('%s cannot be changed' % key)
        for key in self._key_fields + self._unique_fields:
            if self._data[key] != self._old_data[key]:
                if len(self.select(self._env, where = {key:self._data[key]})):
                    raise TracError('%s already exists' % key)

        setsql, setvalues = fields_to_kv_str(self._env, self._non_key_fields,
                                             self._data, sep=',')
        where, values = fields_to_kv_str(self._env, self._key_fields,
                                         self._data)

        sdata = {'where': where,
                 'values': setsql}
        sdata.update(self._meta)
        sql = """UPDATE %(table_name)s SET %(values)s
                 WHERE %(where)s""" % sdata

        old_values = dict((k, v) for k, v in self._old_data.iteritems()
                          if self._data.get(k) != v)
        with self._env.db_transaction as db:
            db(sql, setvalues + values)
            self._update_relations(db, author)
            self._old_data.update(self._data)
            TicketSystem(self._env).reset_ticket_fields()

        ResourceSystem(self._env).resource_changed(self, old_values)
Exemple #11
0
    def update(self, db=None):
        """Update the enum value.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert self.exists, "Cannot update non-existent %s" % self.type
        self.name = simplify_whitespace(self.name)
        if not self.name:
            raise TracError(_("Invalid %(type)s name.", type=self.type))

        with self.env.db_transaction as db:
            self.env.log.info("Updating %s '%s'", self.type, self.name)
            db("UPDATE enum SET name=%s,value=%s WHERE type=%s AND name=%s",
               (self.name, self.value, self.type, self._old_name))
            if self.name != self._old_name:
                # Update tickets
                db(
                    "UPDATE ticket SET %s=%%s WHERE %s=%%s" %
                    (self.ticket_col, self.ticket_col),
                    (self.name, self._old_name))
            TicketSystem(self.env).reset_ticket_fields()

        old_values = dict()
        if self.name != self._old_name:
            old_values["name"] = self._old_name
        if self.value != self._old_value:
            old_values["value"] = self._old_value
        self._old_name = self.name
        self._old_value = self.value
        ResourceSystem(self.env).resource_changed(self, old_values)
Exemple #12
0
    def insert(self, db=None):
        """Add a new enum value.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert not self.exists, "Cannot insert existing %s" % self.type
        self.name = simplify_whitespace(self.name)
        if not self.name:
            raise TracError(_('Invalid %(type)s name.', type=self.type))

        with self.env.db_transaction as db:
            self.env.log.debug("Creating new %s '%s'", self.type, self.name)
            if not self.value:
                row = db(
                    "SELECT COALESCE(MAX(%s), 0) FROM enum WHERE type=%%s" %
                    db.cast('value', 'int'), (self.type, ))
                self.value = int(float(row[0][0])) + 1 if row else 0
            db("INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)",
               (self.type, self.name, self.value))
            TicketSystem(self.env).reset_ticket_fields()

        self._old_name = self.name
        self._old_value = self.value
        ResourceSystem(self.env).resource_created(self)
Exemple #13
0
    def delete(self, db=None):
        """Delete the enum value.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert self.exists, "Cannot delete non-existent %s" % self.type

        with self.env.db_transaction as db:
            self.env.log.info("Deleting %s %s", self.type, self.name)
            db("DELETE FROM enum WHERE type=%s AND value=%s",
               (self.type, self._old_value))
            # Re-order any enums that have higher value than deleted
            # (close gap)
            for enum in self.select(self.env):
                try:
                    if int(enum.value) > int(self._old_value):
                        enum.value = unicode(int(enum.value) - 1)
                        enum.update()
                except ValueError:
                    pass  # Ignore cast error for this non-essential operation
            TicketSystem(self.env).reset_ticket_fields()

        ResourceSystem(self.env).resource_deleted(self)
        self.value = self._old_value = None
        self.name = self._old_name = None
Exemple #14
0
    def insert(self):
        """Create new record in the database"""
        sdata = None
        if self._exists or len(
                self.select(self._env,
                            where=dict([(k, self._data[k])
                                        for k in self._key_fields]))):
            sdata = {
                'keys':
                ','.join(
                    ["%s='%s'" % (k, self._data[k]) for k in self._key_fields])
            }
        elif self._unique_fields and len(
                self.select(self._env,
                            where=dict([(k, self._data[k])
                                        for k in self._unique_fields]))):
            sdata = {
                'keys':
                ','.join([
                    "%s='%s'" % (k, self._data[k]) for k in self._unique_fields
                ])
            }
        if sdata:
            sdata.update(self._meta)
            sdata['values'] = self._data
            raise TracError(
                '%(object_name)s %(keys)s already exists %(values)s' % sdata)

        for key in self._key_fields:
            if self._data[key] is None and key not in self._auto_inc_fields:
                sdata = {'key': key}
                sdata.update(self._meta)
                raise TracError('%(key)s required for %(object_name)s' % sdata)

        fields = [
            field for field in self._all_fields
            if field not in self._auto_inc_fields
        ]
        sdata = {
            'fields': ','.join(fields),
            'values': ','.join(['%s'] * len(fields))
        }
        sdata.update(self._meta)

        sql = """INSERT INTO %(table_name)s (%(fields)s)
                 VALUES (%(values)s)""" % sdata
        with self._env.db_transaction as db:
            cursor = db.cursor()
            cursor.execute(sql, [self._data[f] for f in fields])
            for auto_in_field in self._auto_inc_fields:
                self._data[auto_in_field] = db.get_last_id(
                    cursor, sdata["table_name"], auto_in_field)

            self._exists = True
            self._old_data.update(self._data)
            TicketSystem(self._env).reset_ticket_fields()
        ResourceSystem(self._env).resource_created(self)
Exemple #15
0
def resource_exists(env, resource):
    """Checks for resource existence without actually instantiating a model.

        :return: `True` if the resource exists, `False` if it doesn't
        and `None` in case no conclusion could be made (i.e. when
        `IResourceManager.resource_exists` is not implemented).

        >>> from trac.test import EnvironmentStub
        >>> env = EnvironmentStub()

        >>> resource_exists(env, Resource('dummy-realm', 'dummy-id')) is None
        True
        >>> resource_exists(env, Resource('dummy-realm'))
        False
    """
    manager = ResourceSystem(env).get_resource_manager(resource.realm)
    if manager and hasattr(manager, 'resource_exists'):
        return manager.resource_exists(resource)
    elif resource.id is None:
        return False
Exemple #16
0
def resource_exists(env, resource):
    """Checks for resource existence without actually instantiating a model.

        :return: `True` if the resource exists, `False` if it doesn't
        and `None` in case no conclusion could be made (i.e. when
        `IResourceManager.resource_exists` is not implemented).

        >>> from trac.test import EnvironmentStub
        >>> env = EnvironmentStub()

        >>> resource_exists(env, Resource('dummy-realm', 'dummy-id')) is None
        True
        >>> resource_exists(env, Resource('dummy-realm'))
        False
    """
    manager = ResourceSystem(env).get_resource_manager(resource.realm)
    if manager and hasattr(manager, 'resource_exists'):
        return manager.resource_exists(resource)
    elif resource.id is None:
        return False
Exemple #17
0
    def delete(self, version=None, db=None):
        """Delete one or all versions of a page.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        if not self.exists:
            raise TracError(_("Cannot delete non-existent page"))

        with self.env.db_transaction as db:
            if version is None:
                # Delete a wiki page completely
                db("DELETE FROM wiki WHERE name=%s", (self.name, ))
                self.env.log.info("Deleted page %s", self.name)
            else:
                # Delete only a specific page version
                db("DELETE FROM wiki WHERE name=%s and version=%s",
                   (self.name, version))
                self.env.log.info("Deleted version %d of page %s", version,
                                  self.name)

            if version is None or version == self.version:
                self._fetch(self.name, None)

            if not self.exists:
                # Invalidate page name cache
                del WikiSystem(self.env).pages
                # Delete orphaned attachments
                from trac.attachment import Attachment
                Attachment.delete_all(self.env, 'wiki', self.name)

        # Let change listeners know about the deletion
        if not self.exists:
            for listener in WikiSystem(self.env).change_listeners:
                listener.wiki_page_deleted(self)
            ResourceSystem(self.env).resource_deleted(self)
        else:
            for listener in WikiSystem(self.env).change_listeners:
                if hasattr(listener, 'wiki_page_version_deleted'):
                    listener.wiki_page_version_deleted(self)
            ResourceSystem(self.env).resource_version_deleted(self)
Exemple #18
0
 def _get_helppage_link(self, req):
     link = realm = resource_id = None
     if self.helppage_opt.startswith('/'):
         # Assume valid URL to arbitrary resource inside
         #   of the current Trac environment.
         link = req.href(self.helppage_opt)
     if not link and ':' in self.helppage_opt:
         realm, resource_id = self.helppage_opt.split(':', 1)
         # Validate realm-like prefix against resource realm list,
         #   but exclude 'wiki' to allow deferred page creation.
         rsys = ResourceSystem(self.env)
         if realm in set(rsys.get_known_realms()) - set('wiki'):
             mgr = rsys.get_resource_manager(realm)
             # Handle optional IResourceManager method gracefully.
             try:
                 if mgr.resource_exists(Resource(realm, resource_id)):
                     link = mgr.get_resource_url(resource_id, req.href)
             except AttributeError:
                 # Assume generic resource URL build rule.
                 link = req.href(realm, resource_id)
     if not link:
         if not resource_id:
             # Assume wiki page name for backwards-compatibility.
             resource_id = self.helppage_opt
         # Preserve anchor without 'path_safe' arg (since Trac 0.12.2dev).
         if '#' in resource_id:
             path, anchor = resource_id.split('#', 1)
         else:
             anchor = None
             path = resource_id
         if hasattr(unicode_quote_plus, "safe"):
             # Use method for query string quoting (since Trac 0.13dev).
             anchor = unicode_quote_plus(anchor, safe="?!~*'()")
         else:
             anchor = unicode_quote_plus(anchor)
         link = '#'.join([req.href.wiki(path), anchor])
     return link
Exemple #19
0
    def delete(self, db=None):
        """Delete the ticket.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        with self.env.db_transaction as db:
            Attachment.delete_all(self.env, 'ticket', self.id, db)
            db("DELETE FROM ticket WHERE id=%s", (self.id, ))
            db("DELETE FROM ticket_change WHERE ticket=%s", (self.id, ))
            db("DELETE FROM ticket_custom WHERE ticket=%s", (self.id, ))

        for listener in TicketSystem(self.env).change_listeners:
            listener.ticket_deleted(self)
        ResourceSystem(self.env).resource_deleted(self)
Exemple #20
0
    def delete(self, db=None):
        """Delete the component.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert self.exists, "Cannot delete non-existent component"

        with self.env.db_transaction as db:
            self.env.log.info("Deleting component %s", self.name)
            db("DELETE FROM component WHERE name=%s", (self.name, ))
            TicketSystem(self.env).reset_ticket_fields()

        ResourceSystem(self.env).resource_deleted(self)
        self.name = self._old_name = None
Exemple #21
0
 def delete(self):
     """Deletes the matching record from the database"""
     if not self._exists:
         raise TracError('%(object_name)s does not exist' % self._meta)
     where, values = fields_to_kv_str(self._env, self._key_fields,
                                      self._data)
     sdata = {'where': where}
     sdata.update(self._meta)
     sql = """DELETE FROM %(table_name)s
              WHERE %(where)s""" % sdata
     with self._env.db_transaction as db:
         db(sql, values)
         self._exists = False
         TicketSystem(self._env).reset_ticket_fields()
     ResourceSystem(self._env).resource_deleted(self)
     self._data = dict([(k, None) for k in self._data.keys()])
     self._old_data.update(self._data)
Exemple #22
0
 def get_resource_description(self,
                              resource,
                              format=None,
                              context=None,
                              **kwargs):
     nbhprefix = ResourceSystem(self.env).neighborhood_prefix(
         resource.neighborhood)
     if format == 'compact':
         return '%s#%s' % (nbhprefix, resource.id)
     elif format == 'summary':
         from trac.ticket.model import Ticket
         ticket = Ticket(self.env, resource.id)
         args = [
             ticket[f] for f in ('summary', 'status', 'resolution', 'type')
         ]
         return self.format_summary(*args)
     return nbhprefix + _("Ticket #%(shortname)s", shortname=resource.id)
Exemple #23
0
def resource_from_path(env, path):
    """Find realm and resource ID from resource URL.

    Assuming simple resource paths to convert to Trac resource identifiers.
    """
    if isinstance(path, basestring):
        path = path.strip('/')
        # Special-case: Default TracWiki start page.
        if path == 'wiki':
            path += '/WikiStart'
    for realm in ResourceSystem(env).get_known_realms():
        if path.startswith(realm):
            resource_id = re.sub(realm, '', path, 1).lstrip('/')
            resource = Resource(realm, resource_id)
            if not resource_check:
                return resource
            elif resource_exists(env, resource) in (None, True):
                return get_versioned_resource(env, resource)
Exemple #24
0
    def insert(self, db=None):
        """Insert a new version.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert not self.exists, "Cannot insert existing version"
        self.name = simplify_whitespace(self.name)
        if not self.name:
            raise TracError(_("Invalid version name."))

        with self.env.db_transaction as db:
            self.env.log.debug("Creating new version '%s'", self.name)
            db("INSERT INTO version (name,time,description) VALUES (%s,%s,%s)",
               (self.name, to_utimestamp(self.time), self.description))
            self._old_name = self.name
            TicketSystem(self.env).reset_ticket_fields()

        ResourceSystem(self.env).resource_created(self)
Exemple #25
0
    def update(self, db=None):
        """Update the milestone.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        self.name = simplify_whitespace(self.name)
        if not self.name:
            raise TracError(_("Invalid milestone name."))

        old = self._old.copy()
        with self.env.db_transaction as db:
            old_name = old['name']
            self.env.log.info("Updating milestone '%s'", self.name)
            db(
                """UPDATE milestone
                  SET name=%s, due=%s, completed=%s, description=%s
                  WHERE name=%s
                  """,
                (self.name, to_utimestamp(self.due),
                 to_utimestamp(self.completed), self.description, old_name))
            self.checkin()

            if self.name != old_name:
                # Update milestone field in tickets
                self.env.log.info(
                    "Updating milestone field of all tickets "
                    "associated with milestone '%s'", self.name)
                db("UPDATE ticket SET milestone=%s WHERE milestone=%s",
                   (self.name, old_name))
                TicketSystem(self.env).reset_ticket_fields()

                # Reparent attachments
                Attachment.reparent_all(self.env, 'milestone', old_name,
                                        'milestone', self.name)

        old_values = dict(
            (k, v) for k, v in old.iteritems() if getattr(self, k) != v)
        for listener in TicketSystem(self.env).milestone_change_listeners:
            listener.milestone_changed(self, old_values)
        ResourceSystem(self.env).resource_changed(self, old_values)
Exemple #26
0
    def insert(self, db=None):
        """Insert a new milestone.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        self.name = simplify_whitespace(self.name)
        if not self.name:
            raise TracError(_("Invalid milestone name."))

        with self.env.db_transaction as db:
            self.env.log.debug("Creating new milestone '%s'", self.name)
            db(
                """INSERT INTO milestone (name, due, completed, description)
                  VALUES (%s,%s,%s,%s)
                  """, (self.name, to_utimestamp(self.due),
                        to_utimestamp(self.completed), self.description))
            self.checkin()
            TicketSystem(self.env).reset_ticket_fields()

        for listener in TicketSystem(self.env).milestone_change_listeners:
            listener.milestone_created(self)
        ResourceSystem(self.env).resource_created(self)
Exemple #27
0
    def insert(self, when=None, db=None):
        """Add ticket to database.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        assert not self.exists, 'Cannot insert an existing ticket'

        if 'cc' in self.values:
            self['cc'] = _fixup_cc_list(self.values['cc'])

        # Add a timestamp
        if when is None:
            when = datetime.now(utc)
        self.values['time'] = self.values['changetime'] = when

        # The owner field defaults to the component owner
        if self.values.get('owner') == '< default >':
            default_to_owner = ''
            if self.values.get('component'):
                try:
                    component = Component(self.env, self['component'])
                    default_to_owner = component.owner  # even if it's empty
                except ResourceNotFound:
                    # No such component exists
                    pass
            # If the current owner is "< default >", we need to set it to
            # _something_ else, even if that something else is blank.
            self['owner'] = default_to_owner

        # Perform type conversions
        values = dict(self.values)
        for field in self.time_fields:
            if field in values:
                values[field] = to_utimestamp(values[field])

        # Insert ticket record
        std_fields = []
        custom_fields = []
        for f in self.fields:
            fname = f['name']
            if fname in self.values:
                if f.get('custom'):
                    custom_fields.append(fname)
                else:
                    std_fields.append(fname)
        with self.env.db_transaction as db:
            cursor = db.cursor()
            cursor.execute(
                "INSERT INTO ticket (%s) VALUES (%s)" %
                (','.join(std_fields), ','.join(['%s'] * len(std_fields))),
                [values[name] for name in std_fields])
            tkt_id = db.get_last_id(cursor, 'ticket')

            # Insert custom fields
            if custom_fields:
                db.executemany(
                    """INSERT INTO ticket_custom (ticket, name, value)
                       VALUES (%s, %s, %s)
                    """, [(tkt_id, c, self[c]) for c in custom_fields])

        self.id = tkt_id
        self.resource = self.resource(id=tkt_id)
        self._old = {}

        for listener in TicketSystem(self.env).change_listeners:
            listener.ticket_created(self)
        ResourceSystem(self.env).resource_created(self)

        return self.id
Exemple #28
0
    def save_changes(self,
                     author=None,
                     comment=None,
                     when=None,
                     db=None,
                     cnum='',
                     replyto=None):
        """
        Store ticket changes in the database. The ticket must already exist in
        the database.  Returns False if there were no changes to save, True
        otherwise.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        :since 1.0: the `cnum` parameter is deprecated, and threading should
        be controlled with the `replyto` argument
        """
        assert self.exists, "Cannot update a new ticket"

        if 'cc' in self.values:
            self['cc'] = _fixup_cc_list(self.values['cc'])

        props_unchanged = all(
            self.values.get(k) == v for k, v in self._old.iteritems())
        if (not comment or not comment.strip()) and props_unchanged:
            return False  # Not modified

        if when is None:
            when = datetime.now(utc)
        when_ts = to_utimestamp(when)

        if 'component' in self.values:
            # If the component is changed on a 'new' ticket
            # then owner field is updated accordingly. (#623).
            if self.values.get('status') == 'new' \
                    and 'component' in self._old \
                    and 'owner' not in self._old:
                try:
                    old_comp = Component(self.env, self._old['component'])
                    old_owner = old_comp.owner or ''
                    current_owner = self.values.get('owner') or ''
                    if old_owner == current_owner:
                        new_comp = Component(self.env, self['component'])
                        if new_comp.owner:
                            self['owner'] = new_comp.owner
                except TracError:
                    # If the old component has been removed from the database
                    # we just leave the owner as is.
                    pass

        with self.env.db_transaction as db:
            db("UPDATE ticket SET changetime=%s WHERE id=%s",
               (when_ts, self.id))

            # find cnum if it isn't provided
            if not cnum:
                num = 0
                for ts, old in db(
                        """
                        SELECT DISTINCT tc1.time, COALESCE(tc2.oldvalue,'')
                        FROM ticket_change AS tc1
                        LEFT OUTER JOIN ticket_change AS tc2
                        ON tc2.ticket=%s AND tc2.time=tc1.time
                           AND tc2.field='comment'
                        WHERE tc1.ticket=%s ORDER BY tc1.time DESC
                        """, (self.id, self.id)):
                    # Use oldvalue if available, else count edits
                    try:
                        num += int(old.rsplit('.', 1)[-1])
                        break
                    except ValueError:
                        num += 1
                cnum = str(num + 1)
                if replyto:
                    cnum = '%s.%s' % (replyto, cnum)

            # store fields
            for name in self._old.keys():
                if name in self.custom_fields:
                    for row in db(
                            """SELECT * FROM ticket_custom
                                     WHERE ticket=%s and name=%s
                                     """, (self.id, name)):
                        db(
                            """UPDATE ticket_custom SET value=%s
                              WHERE ticket=%s AND name=%s
                              """, (self[name], self.id, name))
                        break
                    else:
                        db(
                            """INSERT INTO ticket_custom (ticket,name,value)
                              VALUES(%s,%s,%s)
                              """, (self.id, name, self[name]))
                else:
                    db("UPDATE ticket SET %s=%%s WHERE id=%%s" % name,
                       (self[name], self.id))
                db(
                    """INSERT INTO ticket_change
                        (ticket,time,author,field,oldvalue,newvalue)
                      VALUES (%s, %s, %s, %s, %s, %s)
                      """, (self.id, when_ts, author, name, self._old[name],
                            self[name]))

            # always save comment, even if empty
            # (numbering support for timeline)
            db(
                """INSERT INTO ticket_change
                    (ticket,time,author,field,oldvalue,newvalue)
                  VALUES (%s,%s,%s,'comment',%s,%s)
                  """, (self.id, when_ts, author, cnum, comment))

        old_values = self._old
        self._old = {}
        self.values['changetime'] = when

        for listener in TicketSystem(self.env).change_listeners:
            listener.ticket_changed(self, comment, author, old_values)
        context = dict(comment=comment, author=author)
        ResourceSystem(self.env).resource_changed(self, old_values, context)

        return int(cnum.rsplit('.', 1)[-1])
Exemple #29
0
    def save(self, author, comment, remote_addr, t=None, db=None):
        """Save a new version of a page.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        if not validate_page_name(self.name):
            raise TracError(
                _("Invalid Wiki page name '%(name)s'", name=self.name))

        new_text = self.text != self.old_text
        if not new_text and self.readonly == self.old_readonly:
            raise TracError(_("Page not modified"))
        t = t or datetime.now(utc)

        with self.env.db_transaction as db:
            if new_text:
                db(
                    """INSERT INTO wiki (name, version, time, author, ipnr,
                                        text, comment, readonly)
                      VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
                      """,
                    (self.name, self.version + 1, to_utimestamp(t), author,
                     remote_addr, self.text, comment, self.readonly))
                self.version += 1
                self.resource = self.resource(version=self.version)
            else:
                db("UPDATE wiki SET readonly=%s WHERE name=%s",
                   (self.readonly, self.name))
            if self.version == 1:
                # Invalidate page name cache
                del WikiSystem(self.env).pages

        self.author = author
        self.comment = comment
        self.time = t

        for listener in WikiSystem(self.env).change_listeners:
            if self.version == 1:
                listener.wiki_page_added(self)
            else:
                listener.wiki_page_changed(self, self.version, t, comment,
                                           author, remote_addr)
        context = dict(version=self.version,
                       time=t,
                       comment=comment,
                       author=author,
                       remote_addr=remote_addr)
        if self.version == 1:
            ResourceSystem(self.env).resource_created(self, context)
        else:
            old_values = dict()
            if self.readonly != self.old_readonly:
                old_values["readonly"] = self.old_readonly
            if self.text != self.old_text:
                old_values["text"] = self.old_text
            ResourceSystem(self.env).resource_changed(self, old_values,
                                                      context)

        self.old_readonly = self.readonly
        self.old_text = self.text