def __init__(self, message, *args, **kwargs):
        """TracError sub-class with extended i18n support.

        It eases error initialization with messages optionally including
        arguments meant for string substitution after deferred translation.
        """
        title = N_("Registration Error")
        tb = 'show_traceback'
        # Care for the 2nd TracError standard keyword argument only.
        show_traceback = tb in kwargs and kwargs.pop(tb, False)
        TracError.__init__(self, message, title, show_traceback)
        self.msg_args = args
Example #2
0
File: git_fs.py Project: haiku/trac
    def get_changes(self, old_path, old_rev, new_path, new_rev,
                    ignore_ancestry=0):
        # TODO: handle renames/copies, ignore_ancestry
        old_path = self.normalize_path(old_path)
        new_path = self.normalize_path(new_path)
        if old_path != new_path:
            raise TracError(_("Not supported in git_fs"))

        old_rev = self.normalize_rev(old_rev)
        new_rev = self.normalize_rev(new_rev)
        if old_rev == new_rev:
            return

        def get_tree(rev):
            results = self.git.ls_tree(rev, target_path, recursive=True)
            return dict((result[4], result) for result in results)

        def is_dir(mode):
            return mode.startswith('04')

        target_path = old_path.strip('/')
        old_tree = get_tree(old_rev)
        new_tree = get_tree(new_rev)

        with self.git.get_historian(old_rev, target_path) as old_historian:
            with self.git.get_historian(new_rev, target_path) as new_historian:
                for chg in self.git.diff_tree(old_rev, new_rev, target_path):
                    mode1, mode2, obj1, obj2, action, path, path2 = chg
                    kind = Node.DIRECTORY \
                           if is_dir(mode2) or is_dir(mode1) \
                           else Node.FILE

                    change = GitChangeset.action_map[action]
                    old_node = self._get_node(path, old_rev,
                                              old_tree.get(path, False),
                                              old_historian) \
                               if change != Changeset.ADD else None
                    new_node = self._get_node(path, new_rev,
                                              new_tree.get(path, False),
                                              new_historian) \
                               if change != Changeset.DELETE else None

                    yield old_node, new_node, kind, change
Example #3
0
 def _prepare_sortedby(self, sort):
     if not sort:
         return None
     sortedby = []
     for sort_instruction in sort:
         field = sort_instruction.field
         order = sort_instruction.order
         if field.lower() == SCORE:
             if self._is_desc(order):
                 #We can implement tis later by our own ScoreFacet with
                 # "score DESC" support
                 raise TracError(
                     "Whoosh does not support DESC score ordering.")
             sort_condition = whoosh.sorting.ScoreFacet()
         else:
             sort_condition = whoosh.sorting.FieldFacet(
                 field, reverse=self._is_desc(order))
         sortedby.append(sort_condition)
     return sortedby
Example #4
0
    def _process_ticket_request(self, req):
        if not AgiloConfig(self.env).is_agilo_enabled:
            return super(AgiloTicketModule, self)._process_ticket_request(req)

        from agilo.scrum.workflow.api import RuleValidationException
        # Compute the back_to_url
        self._set_back_to_url(req)
        # Check if the delete has been called
        if 'delete' in req.args:
            # load the ticket, delete it and change the ID to another one before
            # sending it to trac
            self._do_delete(req)
        # Process the Ticket the TRAC way
        template = data = content_type = None
        try:
            template, data, content_type = super(
                AgiloTicketModule, self)._process_ticket_request(req)
        except RuleValidationException, e:
            raise TracError(exception_to_unicode(e))
Example #5
0
    def _do_hotcopy(self, dest):
        if os.path.exists(dest):
            raise TracError(
                _("hotcopy can't overwrite existing '%(dest)s'", dest=dest))
        import shutil

        # Bogus statement to lock the database while copying files
        cnx = self.env.get_db_cnx()
        cursor = cnx.cursor()
        cursor.execute("UPDATE system SET name=NULL WHERE name IS NULL")

        try:
            printout(
                _('Hotcopying %(src)s to %(dst)s ...',
                  src=self.env.path,
                  dst=dest))
            db_str = self.env.config.get('trac', 'database')
            prefix, db_path = db_str.split(':', 1)
            if prefix == 'sqlite':
                # don't copy the journal (also, this would fail on Windows)
                db = os.path.join(self.env.path, os.path.normpath(db_path))
                skip = [db + '-journal', db + '-stmtjrnl']
            else:
                skip = []
            try:
                copytree(self.env.path, dest, symlinks=1, skip=skip)
                retval = 0
            except shutil.Error, e:
                retval = 1
                printerr(
                    _('The following errors happened while copying '
                      'the environment:'))
                for (src, dst, err) in e.args[0]:
                    if src in err:
                        printerr('  %s' % err)
                    else:
                        printerr("  %s: '%s'" % (err, src))
        finally:
            # Unlock database
            cnx.rollback()

        printout(_("Hotcopy done."))
        return retval
Example #6
0
    def insert(self, db=None):
        """Insert a new component.

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

        with self.env.db_transaction as db:
            self.env.log.debug("Creating new component '%s'", self.name)
            db(
                """INSERT INTO component (name,owner,description)
                  VALUES (%s,%s,%s)
                  """, (self.name, self.owner, self.description))
            self._old_name = self.name
            TicketSystem(self.env).reset_ticket_fields()
Example #7
0
    def insert(self):
        """Insert a new milestone.
        """
        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)
Example #8
0
 def get_db_version(self, db):
     """Returns the normalized db version (integer). This method can convert 
     the decimal numbers from Agilo 0.6 to integer."""
     fetch_version = super(AgiloInit, self)._fetch_db_version
     db_version = fetch_version(db, self.name)
     if db_version == 0:
         # Agilo versions before 0.7 had different database versions with
         # floating point
         old_version = fetch_version(db, name='agilo-types')
         if old_version == '1.2':
             db_version = 1
         elif old_version != 0:
             msg = _('Unknown version for agilo-types: %s') % old_version
             raise TracError(msg)
     elif db_version == '0.7':
         db_version = 2
     # 'Modern' Agilo versions like 0.7 just return something like '3'.
     db_version = int(db_version)
     return db_version
Example #9
0
 def _prepare_fields_and_view(self):
     self._add_views_selector()
     self.view = self._get_view()
     if self.view:
         self.data[self.DATA_VIEW] = self.view
     fields_to_select = None
     if self.view in self.VIEWS_WITH_KNOWN_FIELDS:
         if self.active_participant:
             fields_in_view = self.active_participant.\
                 get_default_view_fields(self.view)
         elif self.view == self.DATA_VIEW_GRID:
             fields_in_view = self.all_grid_fields
         else:
             raise TracError("Unsupported view: %s" % self.view)
         self.data[self.DATA_HEADERS] = [
             self._create_headers_item(field) for field in fields_in_view
         ]
         fields_to_select = self._add_obligatory_fields(fields_in_view)
     return fields_to_select
Example #10
0
 def needs_upgrade(self):
     """Return whether the environment needs to be upgraded."""
     for participant in self.setup_participants:
         try:
             with self.component_guard(participant, reraise=True):
                 if participant.environment_needs_upgrade():
                     self.log.warning(
                         "Component %s requires an environment upgrade",
                         participant)
                     return True
         except Exception as e:
             raise TracError(
                 _(
                     "Unable to check for upgrade of "
                     "%(module)s.%(name)s: %(err)s",
                     module=participant.__class__.__module__,
                     name=participant.__class__.__name__,
                     err=exception_to_unicode(e)))
     return False
Example #11
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)
Example #12
0
    def upgrade_environment(self, db=None):
        """Each schema version should have its own upgrade module, named
        upgrades/dbN.py, where 'N' is the version number (int).
        """
        db_mgr = DatabaseManager(self.env)
        schema_ver = self.get_schema_version()

        with self.env.db_transaction as db:
            # Is this a new installation?
            if not schema_ver:
                # Perform a single-step install: Create plugin schema and
                # insert default data into the database.
                connector = db_mgr.get_connector()[0]
                for table in db_default.schema:
                    for stmt in connector.to_sql(table):
                        db(stmt)
                for table, cols, vals in db_default.get_data(db):
                    db.executemany("INSERT INTO %s (%s) VALUES (%s)"
                                   % (table, ','.join(cols),
                                      ','.join(['%s'] * len(cols))), vals)
            else:
                # Perform incremental upgrades.
                for i in range(schema_ver + 1, db_default.schema_version + 1):
                    name = 'db%i' % i
                    try:
                        upgrades = __import__('tractags.upgrades', globals(),
                                              locals(), [name])
                        script = getattr(upgrades, name)
                    except AttributeError:
                        raise TracError(_("No upgrade module for version "
                                          "%(num)i (%(version)s.py)", num=i,
                                          version=name))
                    cursor = db.cursor()
                    script.do_upgrade(self.env, i, cursor)
            db("""UPDATE system SET value=%s
                  WHERE name='tags_version'
                  """, (db_default.schema_version,))
            self.log.info("Upgraded TracTags db schema from version %d to %d",
                          schema_ver, db_default.schema_version)

            TicketTagProvider(self.env)._fetch_tkt_tags()
            self.log.info("Synchronized ticket attributes to tags table")
Example #13
0
def do_deploy(self, line):
    argv = self.arg_tokenize(line)
    if not argv[0]:
        self.do_help('deploy')
        return

    target = os.path.normpath(argv[0])
    if os.path.exists(target):
        raise TracError('Destination already exists. Remove and retry.')
    chrome_target = os.path.join(target, 'htdocs')
    script_target = os.path.join(target, 'cgi-bin')

    # Copy static content
    os.makedirs(target)
    os.makedirs(chrome_target)
    from trac.web.chrome import Chrome
    env = self.env_open()
    printout(_("Copying resources from:"))
    for provider in Chrome(env).template_providers:
        paths = list(provider.get_htdocs_dirs())
        if not len(paths):
            continue
        printout('  %s.%s' % (provider.__module__, 
                              provider.__class__.__name__))
        for key, root in paths:
            source = os.path.normpath(root)
            printout('   ', source)
            if os.path.exists(source):
                dest = os.path.join(chrome_target, key)
                copytree(source, dest, overwrite=True)
    
    # Create and copy scripts
    os.makedirs(script_target)
    printout(_("Creating scripts."))
    data = {'env': env, 'executable': sys.executable}
    for script in ('cgi', 'fcgi', 'wsgi'):
        dest = os.path.join(script_target, 'trac.'+script)
        template = Chrome(env).load_template('deploy_trac.'+script, 'text')
        stream = template.generate(**data)
        out = open(dest, 'w')
        stream.render('text', out=out)
        out.close()
Example #14
0
    def get_repository(self, repos_type, repos_dir, params):
        t = datetime(2017, 3, 31, 12, 34, 56, tzinfo=utc)

        def get_changeset(rev):
            return Mock(Changeset, repos, rev, 'message', 'author', t)

        def get_node(path, rev):
            if 'missing' in path:
                raise NoSuchNode(path, rev)
            basename = posixpath.basename(path)
            if 'file' in basename:
                kind = Node.FILE
                entries = ()
            else:
                kind = Node.DIRECTORY
                if 'dir' in basename:
                    entries = ['file.txt']
                else:
                    entries = ['dir1', 'dir2']
                entries = [posixpath.join(path, entry) for entry in entries]
            content = 'Contents for %s' % to_utf8(path)
            node = Mock(Node, repos, path, rev, kind,
                        created_path=path, created_rev=rev,
                        get_entries=lambda: iter(get_node(entry, rev)
                                                 for entry in entries),
                        get_properties=lambda: {},
                        get_content=lambda: io.BytesIO(content),
                        get_content_length=lambda: len(content),
                        get_content_type=lambda: 'application/octet-stream',
                        get_last_modified=lambda: t)
            return node

        if params['name'] == 'raise':
            raise TracError("")
        else:
            repos = Mock(Repository, params['name'], params, self.log,
                         get_youngest_rev=lambda: 1,
                         get_changeset=get_changeset,
                         get_node=get_node,
                         previous_rev=lambda rev, path='': None,
                         next_rev=lambda rev, path='': None)
        return repos
Example #15
0
    def save_metadata(self, metadata):
        """Save the repository metadata."""
        with self.env.db_transaction as db:
            invalidate = False

            # -- check that we're populating the cache for the correct
            #    repository
            repository_dir = metadata.get(CACHE_REPOSITORY_DIR)
            if repository_dir:
                # directory part of the repo name can vary on case insensitive
                # fs
                if os.path.normcase(repository_dir) \
                        != os.path.normcase(self.name):
                    self.log.info("'repository_dir' has changed from %r to %r",
                                  repository_dir, self.name)
                    raise TracError(_("The repository directory has changed, "
                                      "you should resynchronize the "
                                      "repository with: trac-admin $ENV "
                                      "repository resync '%(reponame)s'",
                                      reponame=self.reponame or '(default)'))
            elif repository_dir is None: #
                self.log.info('Storing initial "repository_dir": %s',
                              self.name)
                db("""INSERT INTO repository (id, name, value)
                      VALUES (%s, %s, %s)
                      """, (self.id, CACHE_REPOSITORY_DIR, self.name))
                invalidate = True
            else: # 'repository_dir' cleared by a resync
                self.log.info('Resetting "repository_dir": %s', self.name)
                db("UPDATE repository SET value=%s WHERE id=%s AND name=%s",
                   (self.name, self.id, CACHE_REPOSITORY_DIR))
                invalidate = True

            # -- insert a 'youngeset_rev' for the repository if necessary
            if CACHE_YOUNGEST_REV not in metadata:
                db("""INSERT INTO repository (id, name, value)
                      VALUES (%s, %s, %s)
                      """, (self.id, CACHE_YOUNGEST_REV, ''))
                invalidate = True

            if invalidate:
                del self.metadata
Example #16
0
def add_config_platform_rev_index_to_build(env, db):
    """Adds a unique index on (config, platform, rev) to the bitten_build table.
       Also drops the old index on bitten_build that serves no real purpose anymore."""
    # check for existing duplicates
    duplicates_cursor = db.cursor()
    build_cursor = db.cursor()

    duplicates_cursor.execute("SELECT config, rev, platform FROM bitten_build GROUP BY config, rev, platform HAVING COUNT(config) > 1")
    duplicates_exist = False
    for config, rev, platform in duplicates_cursor.fetchall():
        if not duplicates_exist:
            duplicates_exist = True
            print "\nConfig Name, Revision, Platform :: [<list of build ids>]"
            print "--------------------------------------------------------"

        build_cursor.execute("SELECT id FROM bitten_build WHERE config='%s' AND rev='%s' AND platform='%s'" % (config, rev, platform))
        build_ids = [row[0] for row in build_cursor.fetchall()]
        print "%s, %s, %s :: %s" % (config, rev, platform, build_ids)

    if duplicates_exist:
        print "--------------------------------------------------------\n"
        print "Duplicate builds found. You can obtain help on removing the"
        print "builds you don't want by reading the Bitten upgrade"
        print "documentation at:"
        print "http://bitten.edgewall.org/wiki/Documentation/upgrade.html"
        print "Upgrades cannot be performed until conflicts are resolved."
        print "The upgrade script will now exit with an error:\n"

    duplicates_cursor.close()
    build_cursor.close()

    if not duplicates_exist:
        cursor = db.cursor()
        scheme = parse_scheme(env)
        if scheme == "mysql":
            # 111 = 333 / len(columns in index) -- this is the Trac default
            cursor.execute("CREATE UNIQUE INDEX bitten_build_config_rev_platform_idx ON bitten_build (config(111), rev(111), platform)")
        else:
            cursor.execute("CREATE UNIQUE INDEX bitten_build_config_rev_platform_idx ON bitten_build (config,rev,platform)")
        drop_index(env, db, 'bitten_build', 'bitten_build_config_rev_slave_idx')
    else:
        raise TracError('')
Example #17
0
 def _get_type(self, word):
     # Accept unique abbrevs. of type
     if not word:
         return ''
     if word in self.word2type:
         return self.word2type[word]
     type_ = ''
     for w in self.word2type.iterkeys():
         try:
             if w.startswith(word):
                 t = self.word2type[w]
                 if type_ and type_ != t:
                     return  # 2nd found, not unique
                 type_ = t
         except TypeError as e:
             raise TracError(
                 _("Invalid argument %(arg)s (%(type)s)",
                   arg=word,
                   type=type(word)))
     return type_
Example #18
0
    def get_changeset(self, rev):

        self._log.debug('get_changeset(%r)' % rev)

        if isinstance(rev, int):
            change = rev
        else:
            from p4trac.util import toUnicode
            rev = toUnicode(rev)

            if rev.startswith(u'@'):
                rev = rev[1:]

            try:
                change = int(rev)
            except ValueError:
                raise TracError(u"Invalid changeset number '%s'" % rev)

        return PerforceChangeset(change, self._repos, self._log,
                                 self._job_prefix_length)
Example #19
0
    def source(self, req, args):
        arg = re.compile(":|@").split(args)

        if len(arg) < 2:
            raise TracError('[[Usage: BibAdd(source:file[@rev])')
        elif len(arg) == 2:
            revision = 'latest'
        else:
            revision = arg[2]

        file = arg[1]

        repos = self.env.get_repository()

        # load the file from the repository
        bib = repos.get_node(file, revision)
        file = bib.get_content()
        text = file.read()

        return _extract(text)
Example #20
0
 def _load(self, db=None):
     """Try to load the Sprint from the database"""
     db, handle_ta = get_db_for_write(self.env, db)
     sql_query = "SELECT date, remaining_time FROM %s" \
                 " WHERE task_id=%d ORDER BY date DESC" % (BURNDOWN_TABLE, self.task.id)
     debug(self, "Burndown-SQL Query: %s" % sql_query)
     try:
         history = dict()
         cursor = db.cursor()
         cursor.execute(sql_query)
         for row in cursor.fetchall():
             timestamp, remaining_time = row
             history[timestamp] = remaining_time
         
         self.loaded = True
     except Exception, e:
         error(self, to_unicode(e))
         if handle_ta:
             db.rollback()
         raise TracError("An error occurred while loading Burndown data: %s" % to_unicode(e))
Example #21
0
 def process_request(self, req):
     """Process the HTTP Requests and validate parameters, at least 
     basically, than send a Command Request to a Controller. The 
     response has to be rendered according to the view needs."""
     try:
         handler = self.get_handler(req)
         if handler is not None:
             return self._call_filters_and_handler(req, handler)
         else:
             raise TracError('No handler found for method %s' % req.method)
     except ICommand.NotValidError, e:
         chrome.add_warning(req, unicode(e))
         # not that we update the data, so that the set value are
         # kept safe for re-displaying a page correctly
         data = self.get_data_from_session(req)
         data.update({'error': unicode(e)})
         # This will allow to show the wrong field in a different
         # color or mark them as errors
         data.update({'errors': e.command_attributes.keys()})
         return self.respond(data)
Example #22
0
    def _parse_sort(self, sort_string):
        if not sort_string:
            return None
        sort_terms = sort_string.split(",")
        sort = []

        for term in sort_terms:
            term = term.strip()
            if not term:
                continue
            term_parts = term.split()
            parts_count = len(term_parts)
            if parts_count == 1:
                sort.append(SortInstruction(term_parts[0], ASC))
            elif parts_count == 2:
                sort.append(SortInstruction(term_parts[0], term_parts[1]))
            else:
                raise TracError("Invalid sort term %s " % term)

        return sort if sort else None
Example #23
0
    def needs_upgrade(self, version, name='database_version'):
        """Checks the database version to determine if an upgrade is needed.

        :param version: the expected integer database version.
        :param name: the name of the entry in the SYSTEM table that contains
                     the database version. Defaults to `database_version`,
                     which contains the database version for Trac.

        :return: `True` if the stored version is less than the expected
                  version, `False` if it is equal to the expected version.
        :raises TracError: if the stored version is greater than the expected
                           version.
        """
        dbver = self.get_database_version(name)
        if dbver == version:
            return False
        elif dbver > version:
            raise TracError(_("Need to downgrade %(name)s.", name=name))
        self.log.info("Need to upgrade %s from %d to %d", name, dbver, version)
        return True
Example #24
0
 def default(self, line):
     try:
         if not self.__env:
             self._init_env()
         if self.needs_upgrade is None:
             self.needs_upgrade = self.__env.needs_upgrade()
     except TracError as e:
         raise AdminCommandError(to_unicode(e))
     except Exception as e:
         raise AdminCommandError(exception_to_unicode(e))
     args = self.arg_tokenize(line)
     if args[0] == 'upgrade':
         self.needs_upgrade = None
     elif self.needs_upgrade:
         raise TracError(
             _(
                 'The Trac Environment needs to be upgraded. '
                 'Run:\n\n  trac-admin "%(path)s" upgrade',
                 path=self.envname))
     return self.cmd_mgr.execute_command(*args)
Example #25
0
    def upgrade_environment(self, db):
        self.log.debug("Upgrading timeline environment")
        cursor = db.cursor()

        # Get current database schema version
        db_version = self._get_db_version(cursor)

        # Perform incremental upgrades
        try:
            for i in range(db_version + 1, timeline_db_version + 1):
                script_name = 'db%i' % i
                module = __import__(
                    'multiproject.project.files.db.webdav_events_%s' %
                    script_name, globals(), locals(), ['do_upgrade'])
                module.do_upgrade(self.env, cursor)
                db.commit()
        except:
            raise TracError("Upgrading timeline environment failed")
        finally:
            cursor.close()
Example #26
0
    def upgrade_environment(self, db):
        if self.found_db_version == 0:
            self.environment_created()
            return

        cursor = db.cursor()
        for i in range(self.found_db_version + 1, db_default.version + 1):
            name = 'db%i' % i
            try:
                upgrades = __import__('upgrades', globals(), locals(), [name])
                script = getattr(upgrades, name)
            except AttributeError:
                raise TracError('No upgrade module for %s version %i',
                                db_default.name, i)
            script.do_upgrade(self.env, i, cursor)
            cursor.execute('UPDATE system SET value=%s WHERE name=%s',
                           (db_default.version, db_default.name))
            db.commit()
            self.log.info('Upgraded %s database version from %d to %d',
                          db_default.name, i - 1, i)
Example #27
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)
Example #28
0
def migrate_logs_to_files(env, db):
    """Migrates logs that are stored in the bitten_log_messages table into files."""
    logs_dir = env.config.get("bitten", "logs_dir", "log/bitten")
    if not os.path.isabs(logs_dir):
        logs_dir = os.path.join(env.path, logs_dir)

    if os.path.exists(logs_dir):
        print "Bitten log folder %r already exists" % (logs_dir,)
        print "Upgrade cannot be performed until the existing folder is moved."
        print "The upgrade script will now exit with an error:\n"
        raise TracError("")

    os.makedirs(logs_dir)

    cursor = db.cursor()
    message_cursor = db.cursor()
    update_cursor = db.cursor()
    cursor.execute("SELECT id FROM bitten_log")
    for log_id, in cursor.fetchall():
        filename = "%s.log" % (log_id,)
        message_cursor.execute("SELECT message, level FROM bitten_log_message WHERE log=%s ORDER BY line", (log_id,))
        full_filename = os.path.join(logs_dir, filename)
        message_file = codecs.open(full_filename, "wb", "UTF-8")
        # Note: the original version of this code erroneously wrote to filename + ".level" instead of ".levels", producing unused level files
        level_file = codecs.open(full_filename + '.levels', "wb", "UTF-8")
        for message, level in message_cursor.fetchall() or []:
            message_file.write(to_unicode(message) + "\n")
            level_file.write(to_unicode(level) + "\n")
        message_file.close()
        level_file.close()
        update_cursor.execute("UPDATE bitten_log SET filename=%s WHERE id=%s", (filename, log_id))
        env.log.info("Migrated log %s", log_id)
    env.log.warning("Logs have been migrated from the database to files in %s. "
        "Ensure permissions are set correctly on this file. "
        "Since we presume that the migration worked correctly, "
        "we are now dropping the bitten_log_message table in the database (aren't you glad you backed up)", logs_dir)
    cursor.close()
    cursor = db.cursor()
    cursor.execute("DROP TABLE bitten_log_message")
    cursor.close()
    env.log.warning("We have dropped the bitten_log_message table - you may want to vaccuum/compress your database to save space")
Example #29
0
    def process_request(self, req):
        """Override for TicketModule process_request"""
        ticketid = req.args.get('id')
        productid = req.args.get('productid', '')

        if not ticketid:
            # if /newticket is executed in global scope (from QCT), redirect
            # the request to /products/<first_product_in_DB>/newticket
            if not productid and \
                    not isinstance(self.env, ProductEnvironment):
                default_product = self.env.config.get('ticket',
                                                      'default_product')
                products = Product.select(self.env, {'fields': ['prefix']})
                prefixes = [prod.prefix for prod in products]
                if not default_product or default_product not in prefixes:
                    default_product = products[0].prefix
                req.redirect(req.href.products(default_product, 'newticket'))

            return self._process_newticket_request(req)

        if req.path_info in ('/newticket', '/products'):
            raise TracError(_("id can't be set for a new ticket request."))

        if isinstance(self.env, ProductEnvironment):
            ticket = Ticket(self.env, ticketid)
            if productid and ticket['product'] != productid:
                msg = "Ticket %(id)s in product '%(prod)s' does not exist."
                raise ResourceNotFound(_(msg, id=ticketid, prod=productid),
                                       _("Invalid ticket number"))
            return self._process_ticket_request(req)

        # executed in global scope -> assume ticketid=UID, redirect to product
        with self.env.db_direct_query as db:
            rows = db("""SELECT id,product FROM ticket WHERE uid=%s""",
                      (ticketid, ))
            if not rows:
                msg = "Ticket with uid %(uid)s does not exist."
                raise ResourceNotFound(_(msg, uid=ticketid),
                                       _("Invalid ticket number"))
            tid, prefix = rows[0]
            req.redirect(req.href.products(prefix, 'ticket', tid))
Example #30
0
 def change_sid(self, new_sid):
     assert self.req.authname == 'anonymous', \
            'Cannot change ID of authenticated session'
     assert new_sid, 'Session ID cannot be empty'
     if new_sid == self.sid:
         return
     with self.env.db_transaction as db:
         if db("SELECT sid FROM session WHERE sid=%s", (new_sid,)):
             raise TracError(_("Session '%(id)s' already exists. "
                               "Please choose a different session ID.",
                               id=new_sid),
                             _("Error renaming session"))
         self.env.log.debug("Changing session ID %s to %s", self.sid,
                            new_sid)
         db("UPDATE session SET sid=%s WHERE sid=%s AND authenticated=0",
            (new_sid, self.sid))
         db("""UPDATE session_attribute SET sid=%s 
               WHERE sid=%s and authenticated=0
               """, (new_sid, self.sid))
     self.sid = new_sid
     self.bake_cookie()
Example #31
0
    def insert(self, db=None):
        """Insert a new milestone.

        :since 0.13: the `db` parameter is no longer needed and will be removed
        in version 0.14
        """
        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._to_old()
            TicketSystem(self.env).reset_ticket_fields()

        for listener in TicketSystem(self.env).milestone_change_listeners:
            listener.milestone_created(self)
Example #32
0
def _create_user(req, env, check_permissions=True):
    acctmgr = AccountManager(env)
    username = acctmgr.handle_username_casing(
                        req.args.get('username').strip())
    name = req.args.get('name')
    email = req.args.get('email').strip()
    account = {'username' : username,
               'name' : name,
               'email' : email,
              }
    error = TracError('')
    error.account = account

    if not username:
        error.message = _("Username cannot be empty.")
        raise error

    # Prohibit some user names that are important for Trac and therefor
    # reserved, even if they're not in the permission store for some reason.
    if username in ['authenticated', 'anonymous']:
        error.message = _("Username %s is not allowed.") % username
        raise error

    # NOTE: A user may exist in the password store but not in the permission
    #   store. I.e. this happens, when the user (from the password store)
    #   never logged in into Trac. So we have to perform this test here
    #   and cannot just check for the user being in the permission store.
    #   And obfuscate whether an existing user or group name
    #   was responsible for rejection of this user name.
    if acctmgr.has_user(username):
        error.message = _(
            "Another account or group named %s already exists.") % username
        raise error

    # Check whether there is also a user or a group with that name.
    if check_permissions:
        # NOTE: We can't use 'get_user_permissions(username)' here
        #   as this always returns a list - even if the user doesn't exist.
        #   In this case the permissions of "anonymous" are returned.
        #
        #   Also note that we can't simply compare the result of
        #   'get_user_permissions(username)' to some known set of permission,
        #   i.e. "get_user_permissions('authenticated') as this is always
        #   false when 'username' is the name of an existing permission group.
        #
        #   And again obfuscate whether an existing user or group name
        #   was responsible for rejection of this username.
        for (perm_user, perm_action) in \
                perm.PermissionSystem(env).get_all_permissions():
            if perm_user == username:
                error.message = _(
                    "Another account or group named %s already exists.") \
                    % username
                raise error

    # Always exclude some special characters, i.e. 
    #   ':' can't be used in HtPasswdStore
    #   '[' and ']' can't be used in SvnServePasswordStore
    blacklist = acctmgr.username_char_blacklist
    if containsAny(username, blacklist):
        pretty_blacklist = ''
        for c in blacklist:
            if pretty_blacklist == '':
                pretty_blacklist = tag(' \'', tag.b(c), '\'')
            else:
                pretty_blacklist = tag(pretty_blacklist,
                                       ', \'', tag.b(c), '\'')
        error.message = tag(_(
            "The username must not contain any of these characters:"),
            pretty_blacklist)
        raise error

    # Validation of username passed.

    password = req.args.get('password')
    if not password:
        error.message = _("Password cannot be empty.")
        raise error

    if password != req.args.get('password_confirm'):
        error.message = _("The passwords must match.")
        raise error

    # Validation of password passed.

    if if_enabled(EmailVerificationModule) and acctmgr.verify_email:
        if not email:
            error.message = _("You must specify a valid email address.")
            raise error
        elif not re.match('^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$',
                          email, re.IGNORECASE):
            error.message = _("""The email address specified appears to be
                              invalid. Please specify a valid email address.
                              """)
            raise error
        elif acctmgr.has_email(email):
            error.message = _("""The email address specified is already in
                              use. Please specify a different one.
                              """)
            raise error

    # Validation of email address passed.

    acctmgr.set_password(username, password)

    # INSERT new sid, needed as foreign key in some db schemata later on,
    # at least for PostgreSQL.
    db = env.get_db_cnx()
    cursor = db.cursor()
    cursor.execute("""
        SELECT  COUNT(*)
        FROM    session
        WHERE   sid=%s
        """, (username,))
    exists = cursor.fetchone()
    if not exists:
        cursor.execute("""
            INSERT INTO session
                    (sid,authenticated,last_visit)
            VALUES  (%s,0,0)
            """, (username,))

    for attribute in ('name', 'email'):
        value = req.args.get(attribute)
        if not value:
            continue
        set_user_attribute(env, username, attribute, value)
Example #33
0
    def _do_users(self, req):
        env = self.env
        perm = PermissionSystem(env)
        acctmgr = self.acctmgr
        acctmod = AccountModule(env)
        guard = self.guard
        listing_enabled = acctmgr.supports('get_users')
        create_enabled = acctmgr.supports('set_password')
        password_change_enabled = acctmgr.supports('set_password')
        password_reset_enabled = acctmod.reset_password_enabled
        delete_enabled = acctmgr.supports('delete_user')
        verify_enabled = acctmgr.verify_email and \
                         EmailVerificationModule(env).email_enabled

        account = dict(email=req.args.get('email', '').strip(),
                       name=req.args.get('name', '').strip(),
                       username=acctmgr.handle_username_casing(
                                    req.args.get('username', '').strip()))
        data = {
            '_dgettext': dgettext,
            'acctmgr': account,
            'email_approved': True,
            'listing_enabled': listing_enabled,
            'create_enabled': create_enabled,
            'delete_enabled': delete_enabled,
            'verify_enabled': verify_enabled,
            'ignore_auth_case': self.config.getbool('trac',
                                                    'ignore_auth_case'),
            'password_change_enabled': password_change_enabled,
            'password_reset_enabled': password_reset_enabled
        }
        if req.method == 'GET':
            if 'user' in req.args.iterkeys():
                return self._do_acct_details(req)
            elif req.args.get('max_per_page'):
                return self._do_db_cleanup(req)

        if req.method == 'POST':
            email_approved = req.args.get('email_approved')
            # Preserve selection during a series of requests.
            data['email_approved'] = email_approved

            if req.args.get('add'):
                # Add new user account.
                if create_enabled:
                    # Check request and prime account on success.
                    try:
                        acctmgr.validate_registration(req)
                        # Account email approval for authoritative action.
                        if verify_enabled and email_approved and \
                                account['email']:
                            set_user_attribute(env, account['username'],
                                'email_verification_sent_to', account['email'])
                        # User editor form clean-up.
                        data['acctmgr'] = {}
                    except RegistrationError, e:

                        # Attempt deferred translation.
                        message = gettext(e.message)
                        # Check for (matching number of) message arguments
                        #   before attempting string substitution.
                        if e.msg_args and \
                                len(e.msg_args) == len(re.findall('%s',
                                                                  message)):
                            message = message % e.msg_args
                        data['editor_error'] = Markup(message)
                else:
                    data['editor_error'] = _(
                        "The password store does not support creating users.")
            elif req.args.get('reset') and req.args.get('sel'):
                # Password reset for one or more accounts.
                if password_reset_enabled:
                    sel = req.args.get('sel')
                    sel = isinstance(sel, list) and sel or [sel]
                    for username, name, email in env.get_known_users():
                        if username in sel:
                            acctmod._reset_password(username, email)
                else:
                    data['deletion_error'] = _(
                        "The password reset procedure is not enabled.")
            elif req.args.get('remove') and req.args.get('sel'):
                # Delete one or more accounts.
                if delete_enabled:
                    sel = req.args.get('sel')
                    sel = isinstance(sel, list) and sel or [sel]
                    for account in sel:
                        acctmgr.delete_user(account)
                else:
                    data['deletion_error'] = _(
                        "The password store does not support deleting users.")
            elif req.args.get('change'):
                # Change attributes and or password of existing user account.
                attributes = {
                    'email': _("Email Address"),
                    'name': _("Pre-/Surname (Nickname)"),
                    'password': _("Password")
                    }
                data['success'] = []
                error = TracError('')
                username = acctmgr.handle_username_casing(
                                   req.args.get('username').strip())
                try:
                    if not username:
                        error.account = {'username' : username}
                        error.message = _("Username cannot be empty.")
                        raise error

                    if not acctmgr.has_user(username):
                        error.account = {'username' : username}
                        error.message = _("Unknown user %(user)s.",
                                          user=username)
                        raise error

                    password = req.args.get('password')
                    if password and (password.strip() != ''):
                        if password_change_enabled:
                            if password != req.args.get('password_confirm'):
                                error.message = _("The passwords must match.")
                                raise error
                            acctmgr.set_password(username, password)
                            data['success'].append(attributes.get('password'))
                        else:
                            data['editor_error'] = _(
                                """The password store does not support
                                changing passwords.
                                """)
                    for attribute in ('name', 'email'):
                        value = req.args.get(attribute, '').strip()
                        if value:
                            set_user_attribute(env, username,
                                               attribute, value)
                            data['success'].append(attributes.get(attribute))
                            # Account email approval for authoritative action.
                            if attribute == 'email' and verify_enabled and \
                                    email_approved:
                                set_user_attribute(env, username,
                                    'email_verification_sent_to', value)
                    # User editor form clean-up on success.
                    data['acctmgr'] = {}
                except TracError, e:
                    data['editor_error'] = e.message
                    data['acctmgr'] = getattr(e, 'account', '')
Example #34
0
 def __init__(self, argname, message, title=None, show_traceback=False):
     message = _("Invalid argument") + " `" + argname + "`. " + message
     TracError.__init__(self, message, title, show_traceback)
     self.argname = argname