예제 #1
0
    def render_usermanager_admin_panel(self, req, panel, user, path_info):
        data = dict(messages=[], errors=[],
                    um_profile_fields=UserProfileManager(self.env).get_user_profile_fields())
        
        if req.method=="POST":
            if req.args.has_key("um_profile_picture_remove"):
                if UserProfileManager(self.env).remove_user_file(user["picture_href"]):
                    del user["picture_href"]
                    if user.save():
                        data['messages'].append(_("Successfully removed %s's picture.")%(user.username))
            if req.args.has_key("um_profile_update"):
                for field in data['um_profile_fields'].keys():
                    if req.args.has_key("um_profile_%s"%(field)):
                        if data['um_profile_fields'][field]['type']=='file':
                            user_file_new = UserProfileManager(self.env).get_uploaded_file_href(req, user, field, "um_profile_%s"%(field))
                            user_file_old = user[field]
                            if user_file_new!=user_file_old:
                                user[field] = user_file_new
                                if user_file_old:
                                    try:
                                        UserProfileManager(self.env).remove_user_file(user_file_old)
                                    except Exception, e:
                                        self.log.error(e)
                                        data['errors'].append(_("Unable to remove previous %s=[%s]")%(field, user_file_old))
                        elif data['um_profile_fields'][field]['type']=='multichecks':
                            user[field] = '|'.join(req.args.getlist("um_profile_%s"%(field)))
                        else:
                            user[field] = req.args.get("um_profile_%s"%(field))
                    elif data['um_profile_fields'][field]['type']=='multichecks':
                        # cleanup if none selected
                        user[field]=''

                if user.save():
                    data['messages'].append(_("Successfully updated profile for user [%s].")%(user.username))
예제 #2
0
    def __init__(self, path, log=None, params={}):
        assert have_pysqlite > 0
        self.cnx = None
        if path != ':memory:':
            if not os.access(path, os.F_OK):
                raise TracError(_('Database "%(path)s" not found.', path=path))

            dbdir = os.path.dirname(path)
            if not os.access(path, os.R_OK + os.W_OK) or \
                   not os.access(dbdir, os.R_OK + os.W_OK):
                raise TracError(
                    _('The user %(user)s requires read _and_ write '
                      'permissions to the database file %(path)s '
                      'and the directory it is located in.',
                      user=getuser(), path=path))

        self._active_cursors = weakref.WeakKeyDictionary()
        timeout = int(params.get('timeout', 10.0))
        self._eager = params.get('cursor', 'eager') == 'eager'
        # eager is default, can be turned off by specifying ?cursor=
        if isinstance(path, unicode): # needed with 2.4.0
            path = path.encode('utf-8')
        cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES,
                             check_same_thread=sqlite_version < (3, 3, 1),
                             timeout=timeout)
        # load extensions
        extensions = params.get('extensions', [])
        if len(extensions) > 0:
            cnx.enable_load_extension(True)
            for ext in extensions:
                cnx.load_extension(ext)
            cnx.enable_load_extension(False)

        ConnectionWrapper.__init__(self, cnx, log)
예제 #3
0
    def render_admin_panel(self, req, cat, page, path_info):
        req.perm.require('TRAC_ADMIN')

        status, message = init_admin(self.gitosis_user, self.gitosis_server, self.admrepo, self.env.path)
        data = {}
        if status != 0:
          add_warning(req, _('Error while cloning gitosis-admin repository. Please check your settings and/or passphrase free connection to this repository for the user running trac (in most cases, the web server user)'))
          message = 'return code: '+str(status)+'\nmessage:\n'+message
          if message:
            add_warning(req, _(message))
        repo = replace(os.path.basename(self.config.get('trac', 'repository_dir')), '.git', '')
        if req.method == 'POST':
            config = {}
            self.log.debug('description: '+req.args.get('description'))
            for option in ('daemon', 'gitweb', 'description', 'owner'):
                 config[option] = req.args.get(option)
            self.set_config(repo, config)
            req.redirect(req.href.admin(cat, page))
        repo = replace(os.path.basename(self.config.get('trac', 'repository_dir')), '.git', '')
        if repo != '':
            data = self.get_config(repo)
        self.log.debug('data: %s', str(data))
        if not data:
            data = {}
        for option in ('daemon', 'gitweb', 'description', 'owner'):
            if option not in data:
                data[option] = ''
        data['gitweb'] = data['gitweb'] in _TRUE_VALUES
        data['daemon'] = data['daemon'] in _TRUE_VALUES
        return 'admin_tracgitosis_repo.html', {'repo': data}
예제 #4
0
파일: model.py 프로젝트: trac-ja/trac-ja
    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)
예제 #5
0
 def _do_list(self):
     print_table([(m.name, m.due and
                     format_date(m.due, console_date_format),
                   m.completed and
                     format_datetime(m.completed, console_datetime_format))
                  for m in model.Milestone.select(self.env)],
                 [_("Name"), _("Due"), _("Completed")])
예제 #6
0
 def render_usermanager_admin_panel(self, req, panel, user, path_info):
     
     data={'TYPES':['trac-managed', 'server-managed'],
           'set_password_enabled': AccountManager(self.env).supports('set_password'),
           'delete_enabled': AccountManager(self.env).supports('delete_user')}
     messages=[]
     errors=[]
     
     if req.method=='POST':
         if req.args.has_key('um_account_update_type'):
             if req.args.get('um_account_type')=='trac-managed' and not AccountManager(self.env).has_user(user.username):
                 AccountManager(self.env).set_password(user.username, ''.join([Random().choice('pleaseChangeThisPassword') for x in range(10)]) )
                 messages.append(_("Successfully changed %s's authentication method")%(user.username))
             elif req.args.get('um_account_type')=='server-managed':
                 AccountManager(self.env).delete_user(user.username)
                 messages.append(_("Successfully changed %s's authentication method")%(user.username))
             else:
                 raise TracError("Unknow account type")
         elif req.args.has_key('um_account_change_password'):
             if req.args['um_account_confirm_password'] == req.args['um_account_new_password']:
                 AccountManager(self.env).set_password(user.username, req.args['um_account_new_password'] )
                 messages.append(_("Successfully changed %s's password")%(user.username))
             else:
                 errors.append(_('Passwords don\'t match'))
         else:
             raise TracError("Unknow action")
     
     # Adding type
     data.update(type=AccountManager(self.env).has_user(user.username) and 'trac-managed' or 'server-managed')
     
     return 'admin_um_account.html',{'um_account':data, 'messages':messages, 'errors':errors}
예제 #7
0
    def render_usermanager_admin_panel(self, req, panel, user, path_info):
        user_actions = self._get_user_permissions(user)
        all_user_actions = PermissionSystem(self.env).get_user_permissions(user.username)
        actions = PermissionSystem(self.env).get_actions()+list(set([group for group, permissions in PermissionSystem(self.env).get_all_permissions()]))
        data = dict(actions=actions, 
                    all_user_actions=all_user_actions, 
                    user_actions=user_actions,
                    permsys = PermissionSystem(self.env), 
                    messages=[], errors=[])
 
        if req.method=="POST":
            updated_user_permissions = req.args.getlist('um_permission')
            
            for action in actions:
                if action in updated_user_permissions:
                    if not all_user_actions.has_key(action):
                        try: 
                            PermissionSystem(self.env).grant_permission(user.username, action)
                            data['messages'].append(_("Granted permission [%s] for user [%s].")%(action, user.username))
                        except Exception, e:
                            data['errors'].append(e)
                else:
                    if user_actions.has_key(action):
                        try:
                            PermissionSystem(self.env).revoke_permission(user.username, action)
                            data['messages'].append(_("Revoked permission [%s] for user [%s].")%(action, user.username))
                        except Exception, e:
                            data['errors'].append(e)
예제 #8
0
    def commit(self, req):
        """Perform the operation for all processed rows. Return a list of new 
        or changed tickets"""
        tickets = []

        if not self.do_preview:
            for fields in self.rows:
                ticket = self._get_ticket_from_id_in_csv(req, fields)
                if ticket == None:
                    continue
                ticket_type = self._get_type_for_ticket(fields)
                if not self._may_create_ticket(req.perm, ticket_type):
                    add_warning(req, _("No permission to create a %s.") % ticket_type)
                    continue

                if not self.force:
                    csv_summary = fields[Key.SUMMARY]
                    db_summary = ticket[Key.SUMMARY]
                    if csv_summary != db_summary:
                        msg = _("Ticket %d has a different summary: '%s' (CSV) - '%s' (DB)")
                        add_warning(req, msg % (ticket.id, repr(csv_summary), repr(db_summary)))
                        continue
                tickets.append(ticket)
                ticket.delete()
        return tickets
예제 #9
0
 def check_header(self, header):
     """Check the headers for mandatory fields"""
     if not ((Key.ID in header) or ("ticket" in header)):
         return _("Header must contain '%s' or '%s'") % (Key.ID, "ticket")
     if not (Key.SUMMARY in header):
         return _("Header must contain '%s'") % Key.SUMMARY
     return None
예제 #10
0
파일: api.py 프로젝트: dafrito/trac-mirror
    def _get_connector(self, rtype):
        """Retrieve the appropriate connector for the given repository type.

        Note that the self._lock must be held when calling this method.
        """
        if self._connectors is None:
            # build an environment-level cache for the preferred connectors
            self._connectors = {}
            for connector in self.connectors:
                for type_, prio in connector.get_supported_types() or []:
                    keep = (connector, prio)
                    if type_ in self._connectors and \
                            prio <= self._connectors[type_][1]:
                        keep = None
                    if keep:
                        self._connectors[type_] = keep
        if rtype in self._connectors:
            connector, prio = self._connectors[rtype]
            if prio >= 0: # no error condition
                return connector
            else:
                raise TracError(
                    _('Unsupported version control system "%(name)s"'
                      ': %(error)s', name=rtype,
                      error=to_unicode(connector.error)))
        else:
            raise TracError(
                _('Unsupported version control system "%(name)s": '
                  'Can\'t find an appropriate component, maybe the '
                  'corresponding plugin was not enabled? ', name=rtype))
예제 #11
0
파일: api.py 프로젝트: dafrito/trac-mirror
 def __init__(self, path, rev, msg=None):
     if msg is None:
         msg = _("No node %(path)s at revision %(rev)s", path=path, rev=rev)
     else:
         msg = _("%(msg)s: No node %(path)s at revision %(rev)s",
                 msg=msg, path=path, rev=rev)
     ResourceNotFound.__init__(self, msg, _('No such node'))
예제 #12
0
    def _select_login_action(self, req, remote_user):
        """
        Select login action based on user status.

        - If user is expired, error msg is shown
        - If user is active, user will be logged in
        - If user is inactive, legal process is started
        - Otherwise user has no way of logging in (is banned or disabled)

        """
        user_store = get_userstore()
        user = user_store.getUser(remote_user)
        if not user:
            # This may happen if authentication method is case-insensitive
            add_notice(req, _("Incorrect username or password - please try again"))
            return self._show_login(req)

        # Check if expired
        if user.expires and user.expires <= datetime.utcnow():
            author = user_store.get_user_author(user)
            if author:
                add_warning(req, _('Account expired. Contact {0} for extension'.format(author.getDisplayName())))
            else:
                add_warning(req, _('Account expired. Contact service support for extension'))
            return self._show_login(req)

        # User is authentic but can not log in before knowing he is not banned or disabled or activation required
        if user.status == user.STATUS_INACTIVE and self.env.config.getbool('multiproject', 'login_requires_agreed_terms'):
            return self._request_legal_approval(req, remote_user)

        if user.status in (user.STATUS_ACTIVE, user.STATUS_INACTIVE):
            return self._login_success(req, remote_user)

        add_warning(req, _("User status is '%s'. Can not log in." % user_store.USER_STATUS_LABELS[user.status]))
        return self._show_login(req)
예제 #13
0
파일: api.py 프로젝트: dafrito/trac-mirror
 def modify_repository(self, reponame, changes):
     """Modify attributes of a repository."""
     if is_default(reponame):
         reponame = ''
     new_reponame = changes.get('name', reponame)
     if is_default(new_reponame):
         new_reponame = ''
     rm = RepositoryManager(self.env)
     with self.env.db_transaction as db:
         id = rm.get_repository_id(reponame)
         if reponame != new_reponame:
             if db("""SELECT id FROM repository WHERE name='name' AND
                      value=%s""", (new_reponame,)):
                 raise TracError(_('The repository "%(name)s" already '
                                   'exists.',
                                   name=new_reponame or '(default)'))
         for (k, v) in changes.iteritems():
             if k not in self.repository_attrs:
                 continue
             if k in ('alias', 'name') and is_default(v):
                 v = ''
             if k == 'dir' and not os.path.isabs(v):
                 raise TracError(_("The repository directory must be "
                                   "absolute"))
             db("UPDATE repository SET value=%s WHERE id=%s AND name=%s",
                (v, id, k))
             if not db(
                     "SELECT value FROM repository WHERE id=%s AND name=%s",
                     (id, k)):
                 db("""INSERT INTO repository (id, name, value)
                       VALUES (%s, %s, %s)
                       """, (id, k, v))
     rm.reload_repositories()
예제 #14
0
    def notify(self, resid, subject, author=None):
        self.subject = subject
        config = self.config['notification']
        if not config.getbool('smtp_enabled'):
            return
        from_email, from_name = '', ''
        if author and config.getbool('smtp_from_author'):
            from_email = self.get_smtp_address(author)
            if from_email:
                from_name = self.name_map.get(author, '')
                if not from_name:
                    mo = self.longaddr_re.search(author)
                    if mo:
                        from_name = mo.group(1)
        if not from_email:
            from_email = config.get('smtp_from')
            from_name = config.get('smtp_from_name') or self.env.project_name
        self.replyto_email = config.get('smtp_replyto')
        self.from_email = from_email or self.replyto_email
        self.from_name = from_name
        if not self.from_email and not self.replyto_email:
            message = tag(
                tag.p(_('Unable to send email due to identity crisis.')),
                # convert explicitly to `Fragment` to avoid breaking message
                # when passing `LazyProxy` object to `Fragment`
                tag.p(to_fragment(tag_(
                    "Neither %(from_)s nor %(reply_to)s are specified in the "
                    "configuration.",
                    from_=tag.strong("[notification] smtp_from"),
                    reply_to=tag.strong("[notification] smtp_replyto")))))
            raise TracError(message, _("SMTP Notification Error"))

        Notify.notify(self, resid)
예제 #15
0
파일: admin.py 프로젝트: zjj/trac_hack
 def _sync(self, reponame, rev, clean):
     rm = RepositoryManager(self.env)
     if reponame == '*':
         if rev is not None:
             raise TracError(_('Cannot synchronize a single revision '
                               'on multiple repositories'))
         repositories = rm.get_real_repositories()
     else:
         if is_default(reponame):
             reponame = ''
         repos = rm.get_repository(reponame)
         if repos is None:
             raise TracError(_("Repository '%(repo)s' not found",
                               repo=reponame or '(default)'))
         if rev is not None:
             repos.sync_changeset(rev)
             printout(_('%(rev)s resynced on %(reponame)s.', rev=rev,
                        reponame=repos.reponame or '(default)'))
             return
         repositories = [repos]
     
     db = self.env.get_db_cnx()
     for repos in sorted(repositories, key=lambda r: r.reponame):
         printout(_('Resyncing repository history for %(reponame)s... ',
                    reponame=repos.reponame or '(default)'))
         repos.sync(self._sync_feedback, clean=clean)
         cursor = db.cursor()
         cursor.execute("SELECT count(rev) FROM revision WHERE repos=%s",
                        (repos.id,))
         for cnt, in cursor:
             printout(ngettext('%(num)s revision cached.',
                               '%(num)s revisions cached.', num=cnt))
     printout(_('Done.'))
예제 #16
0
 def _wiki_ctxtnav(self, req, page):
     """Add the normal wiki ctxtnav entries."""
     add_ctxtnav(req, _('Start Page'), req.href.wiki('WikiStart'))
     add_ctxtnav(req, _('Index'), req.href.wiki('TitleIndex'))
     if page.exists:
         add_ctxtnav(req, _('History'), req.href.wiki(page.name,
                                                      action='history'))
예제 #17
0
 def get_navigation_items(self, req):
     if 'WIKI_VIEW' in req.perm('wiki'):
         yield ('mainnav', 'wiki',
                tag.a(_('Wiki'), href=req.href.wiki(), accesskey=1))
         yield ('metanav', 'help',
                tag.a(_('Help/Guide'), href=req.href.wiki('TracGuide'),
                      accesskey=6))
예제 #18
0
파일: console.py 프로젝트: pkdevbox/trac
    def get_initenv_args(self):
        returnvals = []
        printout(_("Creating a new Trac environment at %(envname)s",
                   envname=self.envname))
        printout(_("""
Trac will first ask a few questions about your environment
in order to initialize and prepare the project database.

 Please enter the name of your project.
 This name will be used in page titles and descriptions.
"""))
        dp = 'My Project'
        returnvals.append(raw_input(_("Project Name [%(default)s]> ",
                                      default=dp)).strip() or dp)
        printout(_("""
 Please specify the connection string for the database to use.
 By default, a local SQLite database is created in the environment
 directory. It is also possible to use an already existing
 PostgreSQL database (check the Trac documentation for the exact
 connection string syntax).
"""))
        ddb = 'sqlite:db/trac.db'
        prompt = _("Database connection string [%(default)s]> ", default=ddb)
        returnvals.append(raw_input(prompt).strip() or ddb)
        print()
        return returnvals
예제 #19
0
    def _do_delete(self, req, page):
        if page.readonly:
            req.perm(page.resource).require('WIKI_ADMIN')
        else:
            req.perm(page.resource).require('WIKI_DELETE')

        if 'cancel' in req.args:
            req.redirect(get_resource_url(self.env, page.resource, req.href))

        version = int(req.args.get('version', 0)) or None
        old_version = int(req.args.get('old_version', 0)) or version

        with self.env.db_transaction as db:
            if version and old_version and version > old_version:
                # delete from `old_version` exclusive to `version` inclusive:
                for v in range(old_version, version):
                    page.delete(v + 1, db)
            else:
                # only delete that `version`, or the whole page if `None`
                page.delete(version, db)

        if not page.exists:
            add_notice(req, _("The page %(name)s has been deleted.",
                              name=page.name))
            req.redirect(req.href.wiki())
        else:
            if version and old_version and version > old_version + 1:
                add_notice(req, _('The versions %(from_)d to %(to)d of the '
                                  'page %(name)s have been deleted.',
                            from_=old_version + 1, to=version, name=page.name))
            else:
                add_notice(req, _('The version %(version)d of the page '
                                  '%(name)s has been deleted.',
                                  version=version, name=page.name))
            req.redirect(req.href.wiki(page.name))
예제 #20
0
파일: perm.py 프로젝트: pkdevbox/trac
 def _do_import(self, filename=None):
     permsys = PermissionSystem(self.env)
     try:
         with file_or_std(filename, 'rb') as f:
             encoding = stream_encoding(f)
             linesep = os.linesep if filename else '\n'
             reader = csv.reader(f, lineterminator=linesep)
             for row in reader:
                 if len(row) < 2:
                     raise AdminCommandError(
                         _("Invalid row %(line)d. Expected <user>, "
                           "<action>, [action], [...]",
                           line=reader.line_num))
                 user = to_unicode(row[0], encoding)
                 actions = [to_unicode(action, encoding)
                            for action in row[1:]]
                 if user.isupper():
                     raise AdminCommandError(
                         _("Invalid user %(user)s on line %(line)d: All "
                           "upper-cased tokens are reserved for permission "
                           "names.", user=user, line=reader.line_num))
                 old_actions = self.get_user_perms(user)
                 for action in set(actions) - set(old_actions):
                     permsys.grant_permission(user, action)
     except csv.Error as e:
         raise AdminCommandError(
             _("Cannot import from %(filename)s line %(line)d: %(error)s ",
               filename=path_to_unicode(filename or 'stdin'),
               line=reader.line_num, error=e))
     except IOError as e:
         raise AdminCommandError(
             _("Cannot import from %(filename)s: %(error)s",
               filename=path_to_unicode(filename or 'stdin'),
               error=e.strerror))
예제 #21
0
    def notify(self, resid, subject, author=None):
        self.subject = subject
        config = self.config['notification']
        if not config.getbool('smtp_enabled'):
            return
        from_email, from_name = '', ''
        if author and config.getbool('smtp_from_author'):
            from_email = self.get_smtp_address(author)
            if from_email:
                from_name = self.name_map.get(author, '')
                if not from_name:
                    mo = self.longaddr_re.search(author)
                    if mo:
                        from_name = mo.group(1)
        if not from_email:
            from_email = config.get('smtp_from')
            from_name = config.get('smtp_from_name') or self.env.project_name
        self.replyto_email = config.get('smtp_replyto')
        self.from_email = from_email or self.replyto_email
        self.from_name = from_name
        if not self.from_email and not self.replyto_email:
            raise TracError(tag(
                    tag.p(_('Unable to send email due to identity crisis.')),
                    tag.p(_('Neither %(from_)s nor %(reply_to)s are specified '
                            'in the configuration.',
                            from_=tag.b('notification.from'),
                            reply_to=tag.b('notification.reply_to')))),
                _('SMTP Notification Error'))

        Notify.notify(self, resid)
예제 #22
0
 def get_backlog_list(self, sql, db=None):
     if not db:
         db = self.env.get_db_cnx()
     cursor = db.cursor()
     cursor.execute(sql)
     closed_backlogs = list()
     running_backlogs = list()
     t = datetime.datetime.now()
     now = time.mktime(t.timetuple())
     
     for row in cursor.fetchall():
         _name, _start, _end = row
         if now > _end:
             #handler milestone
             if _end == 0:
                 running_backlogs.append(_name)
             closed_backlogs.append(_name)
         elif now >= _start and now <= _end:
             running_backlogs.append(_name)
         else:
             pass
         
     cursor.close()
             
     backlog_list = [
         {'label': _('Running (by Start Date)'),
          'options': running_backlogs},
         {'label': _('Closed (by End Date)'),
          'options': closed_backlogs},
     ]
     return backlog_list
예제 #23
0
파일: api.py 프로젝트: kopernikus/systrac
 def get_navigation_items(self, req):
     # The 'Admin' navigation item is only visible if at least one
     # admin panel is available
     panels, providers = self._get_panels(req)
     if panels:
         yield ('mainnav', 'monitoring', tag.a(_('Monitoring'), 
                href=req.href.monitoring(), title=_('Monitoring')))
예제 #24
0
파일: roadmap.py 프로젝트: exocad/exotrac
    def _do_delete(self, req, milestone):
        req.perm(milestone.resource).require('MILESTONE_DELETE')

        retarget_to = req.args.get('target') or None
        # Don't translate ticket comment (comment:40:ticket:5658)
        retargeted_tickets = \
            milestone.move_tickets(retarget_to, req.authname,
                "Ticket retargeted after milestone deleted")
        milestone.delete(author=req.authname)
        add_notice(req, _('The milestone "%(name)s" has been deleted.',
                          name=milestone.name))
        if retargeted_tickets:
            add_notice(req, _('The 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 = _("Tickets retargeted after milestone deleted")
            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)))
예제 #25
0
    def _render_editor(self, req, id, copy):
        if id != -1:
            req.perm.require("REPORT_MODIFY")
            for title, description, query in self.env.db_query(
                "SELECT title, description, query FROM report WHERE id=%s", (id,)
            ):
                break
            else:
                raise TracError(_("Report {%(num)s} does not exist.", num=id), _("Invalid Report Number"))
        else:
            req.perm.require("REPORT_CREATE")
            title = description = query = ""

        # an explicitly given 'query' parameter will override the saved query
        query = req.args.get("query", query)

        if copy:
            title += " (copy)"

        if copy or id == -1:
            data = {"title": _("Create New Report"), "action": "new", "error": None}
        else:
            data = {
                "title": _("Edit Report {%(num)d} %(title)s", num=id, title=title),
                "action": "edit",
                "error": req.args.get("error"),
            }

        data["report"] = {"id": id, "title": title, "sql": query, "description": description}
        return data
예제 #26
0
 def _launch(self, encoded_input, *args):
     """Launch a process (cmd), and returns exitcode, stdout + stderr"""
     # Note: subprocess.Popen doesn't support unicode options arguments
     # (http://bugs.python.org/issue1759845) so we have to encode them.
     # Anyway, dot expects utf-8 or the encoding specified with -Gcharset.
     encoded_cmd = []
     for arg in args:
         if isinstance(arg, unicode):
             arg = arg.encode(self.encoding, 'replace')
         encoded_cmd.append(arg)
     p = subprocess.Popen(encoded_cmd, stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     if encoded_input:
         p.stdin.write(encoded_input)
     p.stdin.close()
     out = p.stdout.read()
     err = p.stderr.read()
     failure = p.wait() != 0
     if failure or err or out:
         return (failure, tag.p(tag.br(), _("The command:"), 
                      tag.pre(repr(' '.join(encoded_cmd))), 
                      (_("succeeded but emitted the following output:"),
                       _("failed with the following output:"))[failure],
                      out and tag.pre(repr(out)), 
                      err and tag.pre(repr(err))))
     else:
         return (False, None)
예제 #27
0
    def _render_editor(self, req, id, copy):
        if id != -1:
            req.perm.require('REPORT_MODIFY')
            for title, description, query in self.env.db_query(
                    "SELECT title, description, query FROM report WHERE id=%s",
                    (id,)):
                break
            else:
                raise TracError(_("Report {%(num)s} does not exist.", num=id),
                                _("Invalid Report Number"))
        else:
            req.perm.require('REPORT_CREATE')
            title = description = query = ''

        # an explicitly given 'query' parameter will override the saved query
        query = req.args.get('query', query)

        if copy:
            title += ' (copy)'

        if copy or id == -1:
            data = {'title': _('Create New Report'),
                    'action': 'new',
                    'error': None}
        else:
            data = {'title': _('Edit Report {%(num)d} %(title)s', num=id,
                               title=title),
                    'action': 'edit',
                    'error': req.args.get('error')}

        data['report'] = {'id': id, 'title': title,
                          'sql': query, 'description': description}
        return data
예제 #28
0
파일: web_ui.py 프로젝트: exocad/exotrac
 def pre_process_request(self, req, handler):
     if req.path_info.startswith('/admin/ticket/components/'):
         if req.method == "POST" and 'renamechildren' in req.args:
             if req.args.get('renamechildren') != 'on':
                 return handler # Let trac handle this update
             # First process the parent component. 
             parentcomponentname = req.path_info[25:]
             parentcomponent = model.Component(self.env, parentcomponentname)
             parentcomponent.name = req.args.get('name')
             parentcomponent.owner = req.args.get('owner')
             parentcomponent.description = req.args.get('description')
             try:
                 parentcomponent.update()
             except self.env.db_exc.IntegrityError:
                 raise TracError(_('The component "%(name)s" already '
                                   'exists.', name=parentcomponentname))
                 
             # Now update the child components
             childcomponents = self._get_component_children(parentcomponentname)
             for component in childcomponents:
                 component.name = component.name.replace(parentcomponentname, req.args.get('name'), 1)
                 component.update()
             add_notice(req, _('Your changes have been saved.'))
             req.redirect(req.href.admin('ticket', 'components'))
             
     return handler
예제 #29
0
파일: browser.py 프로젝트: exocad/exotrac
    def process_request(self, req):
        presel = req.args.get('preselected')
        if presel and (presel + '/').startswith(req.href.browser() + '/'):
            req.redirect(presel)

        path = req.args.get('path', '/')
        rev = req.args.get('rev', '')
        if rev.lower() in ('', 'head'):
            rev = None
        format = req.args.get('format')
        order = req.args.get('order', 'name').lower()
        desc = 'desc' in req.args
        xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest'

        rm = RepositoryManager(self.env)
        all_repositories = rm.get_all_repositories()
        reponame, repos, path = rm.get_repository_by_path(path)

        # Repository index
        show_index = not reponame and path == '/'
        if show_index:
            if repos and (as_bool(all_repositories[''].get('hidden'))
                          or not repos.is_viewable(req.perm)):
                repos = None

        if not repos and reponame:
            raise ResourceNotFound(_("Repository '%(repo)s' not found",
                                     repo=reponame))

        if reponame and reponame != repos.reponame: # Redirect alias
            qs = req.query_string
            req.redirect(req.href.browser(repos.reponame or None, path)
                         + ('?' + qs if qs else ''))
        reponame = repos.reponame if repos else None

        # Find node for the requested path/rev
        context = web_context(req)
        node = None
        changeset = None
        display_rev = lambda rev: rev
        if repos:
            try:
                if rev:
                    rev = repos.normalize_rev(rev)
                # If `rev` is `None`, we'll try to reuse `None` consistently,
                # as a special shortcut to the latest revision.
                rev_or_latest = rev or repos.youngest_rev
                node = get_existing_node(req, repos, path, rev_or_latest)
            except NoSuchChangeset, e:
                raise ResourceNotFound(e, _('Invalid changeset number'))
            if node:
                try:
                    # use changeset instance to retrieve branches and tags
                    changeset = repos.get_changeset(node.rev)
                except NoSuchChangeset:
                    pass

            context = context.child(repos.resource.child('source', path,
                                                   version=rev_or_latest))
            display_rev = repos.display_rev
예제 #30
0
    def _prepare_results(self, result_docs, hits):
        ui_docs = [self._process_doc(doc) for doc in result_docs]

        results = Paginator(
            ui_docs,
            self.page - 1,
            self.pagelen,
            hits)

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

        parameters = self.parameters
        if results.has_next_page:
            next_href = parameters.create_href(page=parameters.page + 1)
            add_link(self.req, 'next', next_href, _('Next Page'))

        if results.has_previous_page:
            prev_href = parameters.create_href(page=parameters.page - 1)
            add_link(self.req, 'prev', prev_href, _('Previous Page'))

        self.data[self.DATA_RESULTS] = results
        prevnext_nav(self.req, _('Previous'), _('Next'))
예제 #31
0
    def _do_oauth(self, req):
        try:
            state = req.session['oauth_state']
        except KeyError as exc:
            self._reject_oauth(req, exc)

        oauth = self._oauth_session(req, state)

        # Inner import to avoid a hard dependency on requests-oauthlib.
        import oauthlib
        import requests
        github_oauth_url = os.environ.get("TRAC_GITHUB_OAUTH_URL",
                                          "https://github.com/")
        github_api_url = os.environ.get("TRAC_GITHUB_API_URL",
                                        "https://api.github.com/")
        try:
            oauth.fetch_token(
                github_oauth_url + 'login/oauth/access_token',
                authorization_response=req.abs_href(req.path_info) + '?' +
                req.query_string,
                client_secret=_config_secret(self.client_secret))
        except (oauthlib.oauth2.OAuth2Error,
                requests.exceptions.ConnectionError) as exc:
            self._reject_oauth(req, exc)

        try:
            user = oauth.get(github_api_url + 'user').json()
            # read all required data here to deal with errors correctly
            name = user.get('name')
            email = user.get('email')
            login = user.get('login')
        except Exception as exc:  # pylint: disable=broad-except
            self._reject_oauth(
                req,
                exc,
                reason=_(
                    "An error occurred while communicating with the GitHub API"
                ))
        if self.request_email:
            try:
                for item in oauth.get(github_api_url + 'user/emails').json():
                    if not item['verified']:
                        # ignore unverified email addresses
                        continue
                    if (self.preferred_email_domain
                            and item['email'].lower().endswith(
                                '@' + self.preferred_email_domain.lower())):
                        email = item['email']
                        break
                    if item['primary']:
                        email = item['email']
                        if not self.preferred_email_domain:
                            break
            except Exception as exc:  # pylint: disable=broad-except
                self._reject_oauth(
                    req,
                    exc,
                    reason=_(
                        "An error occurred while retrieving your email address "
                        "from the GitHub API"))
        # Small hack to pass the username to _do_login.
        req.environ['REMOTE_USER'] = self.username_prefix + login
        # Save other available values in the session.
        req.session.setdefault('name', name or '')
        req.session.setdefault('email', email or '')

        return super(GitHubLoginModule, self)._do_login(req)
예제 #32
0
 def get_timeline_filters(self, req):
     if 'WIKI_VIEW' in req.perm:
         yield ('wiki', _('Wiki changes'))
예제 #33
0
    def _render_view(self, req, page):
        version = page.resource.version

        # Add registered converters
        if page.exists:
            for conversion in Mimeview(self.env) \
                              .get_supported_conversions('text/x-trac-wiki'):
                conversion_href = req.href.wiki(page.name,
                                                version=version,
                                                format=conversion.key)
                add_link(req, 'alternate', conversion_href, conversion.name,
                         conversion.in_mimetype)

        data = self._page_data(req, page)
        if page.name == 'WikiStart':
            data['title'] = ''

        ws = WikiSystem(self.env)
        context = web_context(req, page.resource)
        higher, related = [], []
        if not page.exists:
            if 'WIKI_CREATE' not in req.perm(page.resource):
                raise ResourceNotFound(
                    _("Page %(name)s not found", name=page.name))
            formatter = OneLinerFormatter(self.env, context)
            if '/' in page.name:
                parts = page.name.split('/')
                for i in range(len(parts) - 2, -1, -1):
                    name = '/'.join(parts[:i] + [parts[-1]])
                    if not ws.has_page(name):
                        higher.append(
                            ws._format_link(formatter, 'wiki', '/' + name,
                                            name, False))
            else:
                name = page.name
            name = name.lower()
            related = [
                each for each in ws.pages if name in each.lower()
                and 'WIKI_VIEW' in req.perm(self.realm, each)
            ]
            related.sort()
            related = [
                ws._format_link(formatter, 'wiki', '/' + each, each, False)
                for each in related
            ]

        latest_page = WikiPage(self.env, page.name)

        prev_version = next_version = None
        if version:
            try:
                version = int(version)
                for hist in latest_page.get_history():
                    v = hist[0]
                    if v != version:
                        if v < version:
                            if not prev_version:
                                prev_version = v
                                break
                        else:
                            next_version = v
            except ValueError:
                version = None

        prefix = self.PAGE_TEMPLATES_PREFIX
        templates = [
            template[len(prefix):] for template in ws.get_pages(prefix)
            if 'WIKI_VIEW' in req.perm(self.realm, template)
        ]

        # -- prev/up/next links
        if prev_version:
            add_link(req, 'prev', req.href.wiki(page.name,
                                                version=prev_version),
                     _("Version %(num)s", num=prev_version))

        parent = None
        if version:
            add_link(req, 'up', req.href.wiki(page.name, version=None),
                     _("View latest version"))
        elif '/' in page.name:
            parent = page.name[:page.name.rindex('/')]
            add_link(req, 'up', req.href.wiki(parent, version=None),
                     _("View parent page"))

        if next_version:
            add_link(req, 'next', req.href.wiki(page.name,
                                                version=next_version),
                     _('Version %(num)s', num=next_version))

        # Add ctxtnav entries
        if version:
            prevnext_nav(req, _("Previous Version"), _("Next Version"),
                         _("View Latest Version"))
        else:
            if parent:
                add_ctxtnav(req, _('Up'), req.href.wiki(parent))
            self._wiki_ctxtnav(req, page)

        # Plugin content validation
        fields = {'text': page.text}
        for manipulator in self.page_manipulators:
            manipulator.prepare_wiki_page(req, page, fields)
        text = fields.get('text', '')

        data.update({
            'context':
            context,
            'text':
            text,
            'latest_version':
            latest_page.version,
            'attachments':
            AttachmentModule(self.env).attachment_data(context),
            'default_template':
            self.DEFAULT_PAGE_TEMPLATE,
            'templates':
            templates,
            'version':
            version,
            'higher':
            higher,
            'related':
            related,
            'resourcepath_template':
            'wiki_page_path.html',
        })
        add_script(req, 'common/js/folding.js')
        return 'wiki_view.html', data, None
예제 #34
0
 def get_supported_conversions(self):
     yield ('txt', _("Plain Text"), 'txt', 'text/x-trac-wiki', 'text/plain',
            9)
예제 #35
0
    def _render_editor(self, req, page, action='edit', has_collision=False):
        if has_collision:
            if action == 'merge':
                page = WikiPage(self.env, page.name)
                req.perm(page.resource).require('WIKI_VIEW')
            else:
                action = 'collision'

        if not page.exists:
            req.perm(page.resource).require('WIKI_CREATE')
        else:
            req.perm(page.resource).require('WIKI_MODIFY')
        original_text = page.text
        comment = req.args.get('comment', '')
        if 'text' in req.args:
            page.text = req.args.get('text')
        elif 'template' in req.args:
            template = self.PAGE_TEMPLATES_PREFIX + req.args.get('template')
            template_page = WikiPage(self.env, template)
            if template_page and template_page.exists and \
                    'WIKI_VIEW' in req.perm(template_page.resource):
                page.text = template_page.text
        elif 'version' in req.args:
            old_page = WikiPage(self.env, page.name, int(req.args['version']))
            req.perm(page.resource).require('WIKI_VIEW')
            page.text = old_page.text
            comment = _("Reverted to version %(version)s.",
                        version=req.args['version'])
        if action in ('preview', 'diff'):
            page.readonly = 'readonly' in req.args

        author = get_reporter_id(req, 'author')
        defaults = {'editrows': str(self.default_edit_area_height)}
        prefs = dict((key, req.session.get('wiki_%s' % key, defaults.get(key)))
                     for key in ('editrows', 'sidebyside'))

        if 'from_editor' in req.args:
            sidebyside = req.args.get('sidebyside') or None
            if sidebyside != prefs['sidebyside']:
                req.session.set('wiki_sidebyside', int(bool(sidebyside)), 0)
        else:
            sidebyside = prefs['sidebyside']

        if sidebyside:
            editrows = max(int(prefs['editrows']),
                           len(page.text.splitlines()) + 1)
        else:
            editrows = req.args.get('editrows')
            if editrows:
                if editrows != prefs['editrows']:
                    req.session.set('wiki_editrows', editrows,
                                    defaults['editrows'])
            else:
                editrows = prefs['editrows']

        data = self._page_data(req, page, action)
        context = web_context(req, page.resource)
        data.update({
            'context':
            context,
            'author':
            author,
            'comment':
            comment,
            'edit_rows':
            editrows,
            'sidebyside':
            sidebyside,
            'scroll_bar_pos':
            req.args.get('scroll_bar_pos', ''),
            'diff':
            None,
            'attachments':
            AttachmentModule(self.env).attachment_data(context),
            'show_readonly_checkbox':
            ReadonlyWikiPolicy.__name__
            in self.config.get('trac', 'permission_policies')
        })
        if action in ('diff', 'merge'):
            old_text = original_text.splitlines() if original_text else []
            new_text = page.text.splitlines() if page.text else []
            diff_data, changes = self._prepare_diff(req, page, old_text,
                                                    new_text, page.version, '')
            data.update({
                'diff': diff_data,
                'changes': changes,
                'action': 'preview',
                'merge': action == 'merge',
                'longcol': 'Version',
                'shortcol': 'v'
            })
        elif sidebyside and action != 'collision':
            data['action'] = 'preview'

        self._wiki_ctxtnav(req, page)
        Chrome(self.env).add_wiki_toolbars(req)
        Chrome(self.env).add_auto_preview(req)
        add_script(req, 'common/js/folding.js')
        return 'wiki_edit.html', data, None
예제 #36
0
    def _render_diff(self, req, page):
        if not page.exists:
            raise TracError(
                _("Version %(num)s of page \"%(name)s\" does not "
                  "exist",
                  num=req.args.get('version'),
                  name=page.name))

        old_version = req.args.get('old_version')
        if old_version:
            old_version = int(old_version)
            if old_version == page.version:
                old_version = None
            elif old_version > page.version:
                # FIXME: what about reverse diffs?
                old_version = page.resource.version
                page = WikiPage(self.env, page.name, old_version)
                req.perm(page.resource).require('WIKI_VIEW')
        latest_page = WikiPage(self.env, page.name)
        req.perm(latest_page.resource).require('WIKI_VIEW')
        new_version = int(page.version)

        date = author = comment = ipnr = None
        num_changes = 0
        prev_version = next_version = None
        for version, t, a, c, i in latest_page.get_history():
            if version == new_version:
                date = t
                author = a or 'anonymous'
                comment = c or '--'
                ipnr = i or ''
            else:
                if version < new_version:
                    num_changes += 1
                    if not prev_version:
                        prev_version = version
                    if old_version is None or version == old_version:
                        old_version = version
                        break
                else:
                    next_version = version
        if not old_version:
            old_version = 0
        old_page = WikiPage(self.env, page.name, old_version)
        req.perm(old_page.resource).require('WIKI_VIEW')

        # -- text diffs
        old_text = old_page.text.splitlines()
        new_text = page.text.splitlines()
        diff_data, changes = self._prepare_diff(req, page, old_text, new_text,
                                                old_version, new_version)

        # -- prev/up/next links
        if prev_version:
            add_link(
                req, 'prev',
                req.href.wiki(page.name, action='diff', version=prev_version),
                _("Version %(num)s", num=prev_version))
        add_link(req, 'up', req.href.wiki(page.name, action='history'),
                 _('Page history'))
        if next_version:
            add_link(
                req, 'next',
                req.href.wiki(page.name, action='diff', version=next_version),
                _("Version %(num)s", num=next_version))

        data = self._page_data(req, page, 'diff')
        data.update({
            'change': {
                'date': date,
                'author': author,
                'ipnr': ipnr,
                'comment': comment
            },
            'new_version': new_version,
            'old_version': old_version,
            'latest_version': latest_page.version,
            'num_changes': num_changes,
            'longcol': 'Version',
            'shortcol': 'v',
            'changes': changes,
            'diff': diff_data,
        })
        prevnext_nav(req, _("Previous Change"), _("Next Change"),
                     _("Wiki History"))
        return 'wiki_diff.html', data, None
예제 #37
0
    def process_request(self, req):
        action = req.args.get('action', 'view')
        pagename = req.args.get('page', 'WikiStart')
        version = req.args.get('version')
        old_version = req.args.get('old_version')

        if pagename.startswith('/') or pagename.endswith('/') or \
                '//' in pagename:
            pagename = re.sub(r'/{2,}', '/', pagename.strip('/'))
            req.redirect(req.href.wiki(pagename))
        if not validate_page_name(pagename):
            raise TracError(
                _("Invalid Wiki page name '%(name)s'", name=pagename))

        if version is not None:
            try:
                version = int(version)
            except (ValueError, TypeError):
                raise ResourceNotFound(
                    _('No version "%(num)s" for Wiki page "%(name)s"',
                      num=version,
                      name=pagename))

        page = WikiPage(self.env, pagename)
        versioned_page = WikiPage(self.env, pagename, version)

        req.perm(versioned_page.resource).require('WIKI_VIEW')

        if version and versioned_page.version != int(version):
            raise ResourceNotFound(
                _('No version "%(num)s" for Wiki page "%(name)s"',
                  num=version,
                  name=page.name))

        add_stylesheet(req, 'common/css/wiki.css')

        if req.method == 'POST':
            if action == 'edit':
                if 'cancel' in req.args:
                    req.redirect(req.href.wiki(page.name))

                has_collision = int(version) != page.version
                for a in ('preview', 'diff', 'merge'):
                    if a in req.args:
                        action = a
                        break
                versioned_page.text = req.args.get('text')
                valid = self._validate(req, versioned_page)
                if action == 'edit' and not has_collision and valid:
                    return self._do_save(req, versioned_page)
                else:
                    return self._render_editor(req, page, action,
                                               has_collision)
            elif action == 'edit_comment':
                self._do_edit_comment(req, versioned_page)
            elif action == 'delete':
                self._do_delete(req, versioned_page)
            elif action == 'rename':
                return self._do_rename(req, page)
            elif action == 'diff':
                style, options, diff_data = get_diff_options(req)
                contextall = diff_data['options']['contextall']
                req.redirect(
                    req.href.wiki(versioned_page.name,
                                  action='diff',
                                  old_version=old_version,
                                  version=version,
                                  contextall=contextall or None))
        elif action == 'delete':
            return self._render_confirm_delete(req, page)
        elif action == 'rename':
            return self._render_confirm_rename(req, page)
        elif action == 'edit':
            return self._render_editor(req, page)
        elif action == 'edit_comment':
            return self._render_edit_comment(req, versioned_page)
        elif action == 'diff':
            return self._render_diff(req, versioned_page)
        elif action == 'history':
            return self._render_history(req, versioned_page)
        else:
            format = req.args.get('format')
            if format:
                Mimeview(self.env).send_converted(req, 'text/x-trac-wiki',
                                                  versioned_page.text, format,
                                                  versioned_page.name)
            return self._render_view(req, versioned_page)
예제 #38
0
 def get_ticket_field_labels(self):
     """Produce a (name,label) mapping from `get_ticket_fields`."""
     labels = {f['name']: f['label'] for f in self.get_ticket_fields()}
     labels['attachment'] = _("Attachment")
     return labels
예제 #39
0
    def _render_view(self, req, milestone):
        milestone_groups = []
        available_groups = []
        component_group_available = False
        ticket_fields = TicketSystem(self.env).get_ticket_fields()

        # collect fields that can be used for grouping
        for field in ticket_fields:
            if field['type'] == 'select' and field['name'] != 'milestone' \
                    or field['name'] in ('owner', 'reporter'):
                available_groups.append({
                    'name': field['name'],
                    'label': field['label']
                })
                if field['name'] == 'component':
                    component_group_available = True

        # determine the field currently used for grouping
        by = None
        if component_group_available:
            by = 'component'
        elif available_groups:
            by = available_groups[0]['name']
        by = req.args.get('by', by)

        tickets = get_tickets_for_milestone(self.env,
                                            milestone=milestone.name,
                                            field=by)
        tickets = apply_ticket_permissions(self.env, req, tickets)
        stat = get_ticket_stats(self.stats_provider, tickets)

        context = web_context(req, milestone.resource)
        data = {
            'context': context,
            'milestone': milestone,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'available_groups': available_groups,
            'grouped_by': by,
            'groups': milestone_groups
        }
        data.update(milestone_stats_data(self.env, req, stat, milestone.name))

        if by:
            groups = []
            for field in ticket_fields:
                if field['name'] == by:
                    if 'options' in field:
                        groups = field['options']
                        if field.get('optional'):
                            groups.insert(0, '')
                    else:
                        groups = [
                            group for group, in self.env.db_query("""
                                  SELECT DISTINCT COALESCE(%s, '') FROM ticket
                                  ORDER BY COALESCE(%s, '')
                                  """ % (by, by))
                        ]
            max_count = 0
            group_stats = []

            for group in groups:
                values = (group, ) if group else (None, group)
                group_tickets = [t for t in tickets if t[by] in values]
                if not group_tickets:
                    continue

                gstat = get_ticket_stats(self.stats_provider, group_tickets)
                if gstat.count > max_count:
                    max_count = gstat.count

                group_stats.append(gstat)

                gs_dict = {'name': group}
                gs_dict.update(
                    milestone_stats_data(self.env, req, gstat, milestone.name,
                                         by, group))
                milestone_groups.append(gs_dict)

            for idx, gstat in enumerate(group_stats):
                gs_dict = milestone_groups[idx]
                percent = 1.0
                if max_count:
                    percent = float(gstat.count) / float(max_count) * 100
                gs_dict['percent_of_max_total'] = percent

        add_stylesheet(req, 'common/css/roadmap.css')
        add_script(req, 'common/js/folding.js')

        def add_milestone_link(rel, milestone):
            href = req.href.milestone(milestone.name, by=req.args.get('by'))
            add_link(req, rel, href,
                     _('Milestone "%(name)s"', name=milestone.name))

        milestones = [
            m for m in Milestone.select(self.env)
            if 'MILESTONE_VIEW' in req.perm(m.resource)
        ]
        idx = [i for i, m in enumerate(milestones) if m.name == milestone.name]
        if idx:
            idx = idx[0]
            if idx > 0:
                add_milestone_link('first', milestones[0])
                add_milestone_link('prev', milestones[idx - 1])
            if idx < len(milestones) - 1:
                add_milestone_link('next', milestones[idx + 1])
                add_milestone_link('last', milestones[-1])
        prevnext_nav(req, _('Previous Milestone'), _('Next Milestone'),
                     _('Back to Roadmap'))

        return 'milestone_view.html', data, None
예제 #40
0
 def get_admin_panels(self, req):
     if 'BACKLOG_ADMIN' in req.perm:
         yield 'ticket', _("Ticket System"), 'backlogs', _("Backlogs")
예제 #41
0
 def get_timeline_filters(self, req):
     if 'MILESTONE_VIEW' in req.perm:
         yield ('milestone', _('Milestones reached'))
예제 #42
0
 def add_milestone_link(rel, milestone):
     href = req.href.milestone(milestone.name, by=req.args.get('by'))
     add_link(req, rel, href,
              _('Milestone "%(name)s"', name=milestone.name))
예제 #43
0
 def get_navigation_items(self, req):
     if 'ROADMAP_VIEW' in req.perm:
         yield ('mainnav', 'roadmap',
                tag.a(_('Roadmap'), href=req.href.roadmap(), accesskey=3))
예제 #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
 def get_search_filters(self, req):
     if 'MILESTONE_VIEW' in req.perm:
         yield ('milestone', _('Milestones'))
예제 #46
0
    def _render_ics(self, req, milestones):
        req.send_response(200)
        req.send_header('Content-Type', 'text/calendar;charset=utf-8')
        buf = StringIO()

        from trac.ticket import Priority
        priorities = {}
        for priority in Priority.select(self.env):
            priorities[priority.name] = float(priority.value)

        def get_priority(ticket):
            value = priorities.get(ticket['priority'])
            if value:
                return int(
                    (len(priorities) + 8 * value - 9) / (len(priorities) - 1))

        def get_status(ticket):
            status = ticket['status']
            if status == 'new' or status == 'reopened' and not ticket['owner']:
                return 'NEEDS-ACTION'
            elif status == 'assigned' or status == 'reopened':
                return 'IN-PROCESS'
            elif status == 'closed':
                if ticket['resolution'] == 'fixed':
                    return 'COMPLETED'
                else:
                    return 'CANCELLED'
            else:
                return ''

        def escape_value(text):
            s = ''.join(map(lambda c: '\\' + c if c in ';,\\' else c, text))
            return '\\n'.join(re.split(r'[\r\n]+', s))

        def write_prop(name, value, params={}):
            text = ';'.join([name] + [k + '=' + v for k, v in params.items()]) \
                 + ':' + escape_value(value)
            firstline = 1
            while text:
                if not firstline:
                    text = ' ' + text
                else:
                    firstline = 0
                buf.write(text[:75] + CRLF)
                text = text[75:]

        def write_date(name, value, params={}):
            params['VALUE'] = 'DATE'
            write_prop(name, format_date(value, '%Y%m%d', req.tz), params)

        def write_utctime(name, value, params={}):
            write_prop(name, format_datetime(value, '%Y%m%dT%H%M%SZ', utc),
                       params)

        host = req.base_url[req.base_url.find('://') + 3:]
        user = req.args.get('user', 'anonymous')

        write_prop('BEGIN', 'VCALENDAR')
        write_prop('VERSION', '2.0')
        write_prop('PRODID',
                   '-//Edgewall Software//NONSGML Trac %s//EN' % __version__)
        write_prop('METHOD', 'PUBLISH')
        write_prop('X-WR-CALNAME',
                   self.env.project_name + ' - ' + _('Roadmap'))
        write_prop('X-WR-CALDESC', self.env.project_description)
        write_prop('X-WR-TIMEZONE', str(req.tz))

        for milestone in milestones:
            uid = '<%s/milestone/%s@%s>' % (req.base_path, milestone.name,
                                            host)
            if milestone.due:
                write_prop('BEGIN', 'VEVENT')
                write_prop('UID', uid)
                write_utctime('DTSTAMP', milestone.due)
                write_date('DTSTART', milestone.due)
                write_prop('SUMMARY',
                           _('Milestone %(name)s', name=milestone.name))
                write_prop('URL', req.abs_href.milestone(milestone.name))
                if milestone.description:
                    write_prop('DESCRIPTION', milestone.description)
                write_prop('END', 'VEVENT')
            tickets = get_tickets_for_milestone(self.env,
                                                milestone=milestone.name,
                                                field='owner')
            tickets = apply_ticket_permissions(self.env, req, tickets)
            for tkt_id in [
                    ticket['id'] for ticket in tickets
                    if ticket['owner'] == user
            ]:
                ticket = Ticket(self.env, tkt_id)
                write_prop('BEGIN', 'VTODO')
                write_prop('UID',
                           '<%s/ticket/%s@%s>' % (req.base_path, tkt_id, host))
                if milestone.due:
                    write_prop('RELATED-TO', uid)
                    write_date('DUE', milestone.due)
                write_prop(
                    'SUMMARY',
                    _('Ticket #%(num)s: %(summary)s',
                      num=ticket.id,
                      summary=ticket['summary']))
                write_prop('URL', req.abs_href.ticket(ticket.id))
                write_prop('DESCRIPTION', ticket['description'])
                priority = get_priority(ticket)
                if priority:
                    write_prop('PRIORITY', unicode(priority))
                write_prop('STATUS', get_status(ticket))
                if ticket['status'] == 'closed':
                    for time, in self.env.db_query(
                            """
                            SELECT time FROM ticket_change
                            WHERE ticket=%s AND field='status'
                            ORDER BY time desc LIMIT 1
                            """, (ticket.id, )):
                        write_utctime('COMPLETED', from_utimestamp(time))
                write_prop('END', 'VTODO')
        write_prop('END', 'VCALENDAR')

        ics_str = buf.getvalue().encode('utf-8')
        req.send_header('Content-Length', len(ics_str))
        req.end_headers()
        req.write(ics_str)
        raise RequestDone
예제 #47
0
 def get_annotation_type(self):
     return 'lineno', _('Line'), _('Line numbers')
예제 #48
0
    def get_ticket_group_stats(self, ticket_ids):
        total_cnt = len(ticket_ids)
        all_statuses = set(TicketSystem(self.env).get_all_status())
        status_cnt = {}
        for s in all_statuses:
            status_cnt[s] = 0
        if total_cnt:
            for status, count in self.env.db_query("""
                    SELECT status, count(status) FROM ticket
                    WHERE id IN (%s) GROUP BY status
                    """ % ",".join(str(x) for x in sorted(ticket_ids))):
                status_cnt[status] = count

        stat = TicketGroupStats(_('ticket status'), _('tickets'))
        remaining_statuses = set(all_statuses)
        groups = self._get_ticket_groups()
        catch_all_group = None
        # we need to go through the groups twice, so that the catch up group
        # doesn't need to be the last one in the sequence
        for group in groups:
            status_str = group['status'].strip()
            if status_str == '*':
                if catch_all_group:
                    raise TracError(
                        _(
                            "'%(group1)s' and '%(group2)s' milestone groups "
                            "both are declared to be \"catch-all\" groups. "
                            "Please check your configuration.",
                            group1=group['name'],
                            group2=catch_all_group['name']))
                catch_all_group = group
            else:
                group_statuses = set([s.strip()
                                      for s in status_str.split(',')]) \
                                      & all_statuses
                if group_statuses - remaining_statuses:
                    raise TracError(
                        _(
                            "'%(groupname)s' milestone group reused status "
                            "'%(status)s' already taken by other groups. "
                            "Please check your configuration.",
                            groupname=group['name'],
                            status=', '.join(group_statuses -
                                             remaining_statuses)))
                else:
                    remaining_statuses -= group_statuses
                group['statuses'] = group_statuses
        if catch_all_group:
            catch_all_group['statuses'] = remaining_statuses
        for group in groups:
            group_cnt = 0
            query_args = {}
            for s, cnt in status_cnt.iteritems():
                if s in group['statuses']:
                    group_cnt += cnt
                    query_args.setdefault('status', []).append(s)
            for arg in [
                    kv for kv in group.get('query_args', '').split(',')
                    if '=' in kv
            ]:
                k, v = [a.strip() for a in arg.split('=', 1)]
                query_args.setdefault(k, []).append(v)
            stat.add_interval(group.get('label', group['name']),
                              group_cnt, query_args,
                              group.get('css_class', group['name']),
                              as_bool(group.get('overall_completion')))
        stat.refresh_calcs()
        return stat
예제 #49
0
파일: web_ui.py 프로젝트: ohanar/trac
 def get_admin_panels(self, req):
     if 'TRAC_ADMIN' in req.perm:
         yield ('general', _('General'), 'plugin', _('Plugins'))
예제 #50
0
    def render(self,
               context,
               mimetype,
               content,
               filename=None,
               url=None,
               annotations=None,
               force_source=False):
        """Render an XHTML preview of the given `content`.

        `content` is the same as an `IHTMLPreviewRenderer.render`'s
        `content` argument.

        The specified `mimetype` will be used to select the most appropriate
        `IHTMLPreviewRenderer` implementation available for this MIME type.
        If not given, the MIME type will be infered from the filename or the
        content.

        Return a string containing the XHTML text.

        When rendering with an `IHTMLPreviewRenderer` fails, a warning is added
        to the request associated with the context (if any), unless the
        `disable_warnings` hint is set to `True`.
        """
        if not content:
            return ''
        if not isinstance(context, RenderingContext):
            raise TypeError("RenderingContext expected (since 0.11)")

        # Ensure we have a MIME type for this content
        full_mimetype = mimetype
        if not full_mimetype:
            if hasattr(content, 'read'):
                content = content.read(self.max_preview_size)
            full_mimetype = self.get_mimetype(filename, content)
        if full_mimetype:
            mimetype = ct_mimetype(full_mimetype)  # split off charset
        else:
            mimetype = full_mimetype = 'text/plain'  # fallback if not binary

        # Determine candidate `IHTMLPreviewRenderer`s
        candidates = []
        for renderer in self.renderers:
            qr = renderer.get_quality_ratio(mimetype)
            if qr > 0:
                candidates.append((qr, renderer))
        candidates.sort(lambda x, y: cmp(y[0], x[0]))

        # Wrap file-like object so that it can be read multiple times
        if hasattr(content, 'read'):
            content = Content(content, self.max_preview_size)

        # First candidate which renders successfully wins.
        # Also, we don't want to expand tabs more than once.
        expanded_content = None
        for qr, renderer in candidates:
            if force_source and not getattr(renderer, 'returns_source', False):
                continue  # skip non-source renderers in force_source mode
            if isinstance(content, Content):
                content.reset()
            try:
                ann_names = ', '.join(annotations) if annotations else \
                           'no annotations'
                self.log.debug('Trying to render HTML preview using %s [%s]',
                               renderer.__class__.__name__, ann_names)

                # check if we need to perform a tab expansion
                rendered_content = content
                if getattr(renderer, 'expand_tabs', False):
                    if expanded_content is None:
                        content = content_to_unicode(self.env, content,
                                                     full_mimetype)
                        expanded_content = content.expandtabs(self.tab_width)
                    rendered_content = expanded_content

                result = renderer.render(context, full_mimetype,
                                         rendered_content, filename, url)
                if not result:
                    continue

                if not (force_source
                        or getattr(renderer, 'returns_source', False)):
                    # Direct rendering of content
                    if isinstance(result, basestring):
                        if not isinstance(result, unicode):
                            result = to_unicode(result)
                        return Markup(to_unicode(result))
                    elif isinstance(result, Fragment):
                        return result.generate()
                    else:
                        return result

                # Render content as source code
                if annotations:
                    marks = context.req.args.get('marks') if context.req \
                            else None
                    if marks:
                        context.set_hints(marks=marks)
                    return self._render_source(context, result, annotations)
                else:
                    if isinstance(result, list):
                        result = Markup('\n').join(result)
                    return tag.div(class_='code')(tag.pre(result)).generate()

            except Exception as e:
                self.log.warning('HTML preview using %s with %r failed: %s',
                                 renderer.__class__.__name__, context,
                                 exception_to_unicode(e, traceback=True))
                if context.req and not context.get_hint('disable_warnings'):
                    from trac.web.chrome import add_warning
                    add_warning(
                        context.req,
                        _("HTML preview using %(renderer)s failed (%(err)s)",
                          renderer=renderer.__class__.__name__,
                          err=exception_to_unicode(e)))
예제 #51
0
파일: web_ui.py 프로젝트: ohanar/trac
 def get_admin_panels(self, req):
     if 'PERMISSION_GRANT' in req.perm or 'PERMISSION_REVOKE' in req.perm:
         yield ('general', _('General'), 'perm', _('Permissions'))
예제 #52
0
파일: web_ui.py 프로젝트: ohanar/trac
    def process_request(self, req):
        panels, providers = self._get_panels(req)
        if not panels:
            raise HTTPNotFound(_('No administration panels available'))

        def _panel_order(p1, p2):
            if p1[::2] == ('general', 'basics'):
                return -1
            elif p2[::2] == ('general', 'basics'):
                return 1
            elif p1[0] == 'general':
                if p2[0] == 'general':
                    return cmp(p1[1:], p2[1:])
                return -1
            elif p2[0] == 'general':
                if p1[0] == 'general':
                    return cmp(p1[1:], p2[1:])
                return 1
            return cmp(p1, p2)

        panels.sort(_panel_order)

        cat_id = req.args.get('cat_id') or panels[0][0]
        panel_id = req.args.get('panel_id')
        path_info = req.args.get('path_info')
        if not panel_id:
            try:
                panel_id = filter(lambda panel: panel[0] == cat_id,
                                  panels)[0][2]
            except IndexError:
                raise HTTPNotFound(_('Unknown administration panel'))

        provider = providers.get((cat_id, panel_id), None)
        if not provider:
            raise HTTPNotFound(_('Unknown administration panel'))

        if hasattr(provider, 'render_admin_panel'):
            template, data = provider.render_admin_panel(
                req, cat_id, panel_id, path_info)

        else:  # support for legacy WebAdmin panels
            data = {}
            cstmpl, ct = provider.process_admin_request(
                req, cat_id, panel_id, path_info)
            output = cstmpl.render()

            title = _("Untitled")
            for panel in panels:
                if (panel[0], panel[2]) == (cat_id, panel_id):
                    title = panel[3]

            data.update({'page_title': title, 'page_body': HTML(output)})
            template = 'admin_legacy.html'

        data.update({
            'active_cat':
            cat_id,
            'active_panel':
            panel_id,
            'panel_href':
            partial(req.href, 'admin', cat_id, panel_id),
            'panels': [{
                'category': {
                    'id': panel[0],
                    'label': panel[1]
                },
                'panel': {
                    'id': panel[2],
                    'label': panel[3]
                }
            } for panel in panels]
        })

        add_stylesheet(req, 'common/css/admin.css')
        return template, data, None
예제 #53
0
파일: web_ui.py 프로젝트: ohanar/trac
 def get_admin_panels(self, req):
     if 'TRAC_ADMIN' in req.perm:
         yield ('general', _('General'), 'logging', _('Logging'))
예제 #54
0
파일: web_ui.py 프로젝트: ohanar/trac
    def render_admin_panel(self, req, cat, page, path_info):
        perm = PermissionSystem(self.env)
        all_permissions = perm.get_all_permissions()
        all_actions = perm.get_actions()

        if req.method == 'POST':
            subject = req.args.get('subject', '').strip()
            action = req.args.get('action')
            group = req.args.get('group', '').strip()

            if subject and subject.isupper() or \
                   group and group.isupper():
                raise TracError(
                    _('All upper-cased tokens are reserved for '
                      'permission names'))

            # Grant permission to subject
            if req.args.get('add') and subject and action:
                req.perm.require('PERMISSION_GRANT')
                if action not in all_actions:
                    raise TracError(_('Unknown action'))
                req.perm.require(action)
                if (subject, action) not in all_permissions:
                    perm.grant_permission(subject, action)
                    add_notice(
                        req,
                        _(
                            'The subject %(subject)s has been '
                            'granted the permission %(action)s.',
                            subject=subject,
                            action=action))
                    req.redirect(req.href.admin(cat, page))
                else:
                    add_warning(
                        req,
                        _(
                            'The permission %(action)s was already '
                            'granted to %(subject)s.',
                            action=action,
                            subject=subject))

            # Add subject to group
            elif req.args.get('add') and subject and group:
                req.perm.require('PERMISSION_GRANT')
                for action in perm.get_user_permissions(group):
                    if not action in all_actions:  # plugin disabled?
                        self.env.log.warn("Adding %s to group %s: " \
                            "Permission %s unavailable, skipping perm check." \
                            % (subject, group, action))
                    else:
                        req.perm.require(action)
                if (subject, group) not in all_permissions:
                    perm.grant_permission(subject, group)
                    add_notice(
                        req,
                        _(
                            'The subject %(subject)s has been added '
                            'to the group %(group)s.',
                            subject=subject,
                            group=group))
                    req.redirect(req.href.admin(cat, page))
                else:
                    add_warning(
                        req,
                        _(
                            'The subject %(subject)s was already '
                            'added to the group %(group)s.',
                            subject=subject,
                            group=group))

            # Remove permissions action
            elif req.args.get('remove') and req.args.get('sel'):
                req.perm.require('PERMISSION_REVOKE')
                sel = req.args.get('sel')
                sel = sel if isinstance(sel, list) else [sel]
                for key in sel:
                    subject, action = key.split(':', 1)
                    subject = unicode_from_base64(subject)
                    action = unicode_from_base64(action)
                    if (subject, action) in perm.get_all_permissions():
                        perm.revoke_permission(subject, action)
                add_notice(req,
                           _('The selected permissions have been '
                             'revoked.'))
                req.redirect(req.href.admin(cat, page))

        perms = [perm for perm in all_permissions if perm[1].isupper()]
        groups = [perm for perm in all_permissions if not perm[1].isupper()]

        return 'admin_perms.html', {
            'actions': all_actions,
            'perms': perms,
            'groups': groups,
            'unicode_to_base64': unicode_to_base64
        }
예제 #55
0
파일: console.py 프로젝트: zxfly/trac
 def initenv_error(msg):
     printerr(_("Initenv for '%(env)s' failed.", env=self.envname),
              "\n%s" % msg)
예제 #56
0
파일: web_ui.py 프로젝트: ohanar/trac
    def render_admin_panel(self, req, cat, page, path_info):
        log_type = self.env.log_type
        log_level = self.env.log_level
        log_file = self.env.log_file
        log_dir = os.path.join(self.env.path, 'log')

        log_types = [
            dict(name='none',
                 label=_('None'),
                 selected=log_type == 'none',
                 disabled=False),
            dict(name='stderr',
                 label=_('Console'),
                 selected=log_type == 'stderr',
                 disabled=False),
            dict(name='file',
                 label=_('File'),
                 selected=log_type == 'file',
                 disabled=False),
            dict(name='syslog',
                 label=_('Syslog'),
                 disabled=os.name != 'posix',
                 selected=log_type in ('unix', 'syslog')),
            dict(name='eventlog',
                 label=_('Windows event log'),
                 disabled=os.name != 'nt',
                 selected=log_type in ('winlog', 'eventlog', 'nteventlog')),
        ]

        log_levels = ['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']

        if req.method == 'POST':
            changed = False

            new_type = req.args.get('log_type')
            if new_type not in [t['name'] for t in log_types]:
                raise TracError(_('Unknown log type %(type)s', type=new_type),
                                _('Invalid log type'))
            if new_type != log_type:
                self.config.set('logging', 'log_type', new_type)
                changed = True
                log_type = new_type

            if log_type == 'none':
                self.config.remove('logging', 'log_level')
                changed = True
            else:
                new_level = req.args.get('log_level')
                if new_level not in log_levels:
                    raise TracError(
                        _('Unknown log level %(level)s', level=new_level),
                        _('Invalid log level'))
                if new_level != log_level:
                    self.config.set('logging', 'log_level', new_level)
                    changed = True
                    log_level = new_level

            if log_type == 'file':
                new_file = req.args.get('log_file', 'trac.log')
                if new_file != log_file:
                    self.config.set('logging', 'log_file', new_file)
                    changed = True
                    log_file = new_file
                if not log_file:
                    raise TracError(_('You must specify a log file'),
                                    _('Missing field'))
            else:
                self.config.remove('logging', 'log_file')
                changed = True

            if changed:
                _save_config(self.config, req, self.log),
            req.redirect(req.href.admin(cat, page))

        data = {
            'type': log_type,
            'types': log_types,
            'level': log_level,
            'levels': log_levels,
            'file': log_file,
            'dir': log_dir
        }
        return 'admin_logging.html', {'log': data}
예제 #57
0
파일: prefs.py 프로젝트: wataash/trac
    def render_preference_panel(self, req, panel, path_info=None):
        if req.method == 'POST':
            action_arg = req.args.getfirst('action', '').split('_', 1)
            if len(action_arg) == 2:
                action, arg = action_arg
                handler = self.post_handlers.get(action)
                if handler:
                    handler(arg, req)
                    add_notice(req, _("Your preferences have been saved."))
            req.redirect(req.href.prefs('notification'))

        rules = {}
        subscribers = []
        formatters = {}
        selected_format = {}
        defaults = []

        for i in self.subscribers:
            description = i.description()
            if not description:
                continue
            if not req.session.authenticated and i.requires_authentication():
                continue
            subscribers.append({
                'class': i.__class__.__name__,
                'description': description
            })
            if hasattr(i, 'default_subscriptions'):
                defaults.extend(i.default_subscriptions())
        desc_map = dict((s['class'], s['description']) for s in subscribers)

        for t in self._iter_transports():
            rules[t] = []
            formatters[t] = self._get_supported_styles(t)
            selected_format[t] = req.session.get('notification.format.%s' % t)
            for r in self._iter_rules(req, t):
                description = desc_map.get(r['class'])
                if description:
                    values = {'description': description}
                    values.update(
                        (key, r[key])
                        for key in ('id', 'adverb', 'class', 'priority'))
                    rules[t].append(values)

        default_rules = {}
        for r in sorted(defaults, key=itemgetter(3)):  # sort by priority
            klass, dist, format, priority, adverb = r
            default_rules.setdefault(dist, [])
            description = desc_map.get(klass)
            if description:
                default_rules[dist].append({
                    'adverb': adverb,
                    'description': description
                })

        data = {
            'rules': rules,
            'subscribers': subscribers,
            'formatters': formatters,
            'selected_format': selected_format,
            'default_rules': default_rules,
            'adverbs': ('always', 'never'),
            'adverb_labels': {
                'always': _("Notify"),
                'never': _("Never notify")
            }
        }
        Chrome(self.env).add_jquery_ui(req)
        return 'prefs_notification.html', dict(data=data)
예제 #58
0
파일: web_ui.py 프로젝트: ohanar/trac
 def get_admin_panels(self, req):
     if 'TRAC_ADMIN' in req.perm:
         yield ('general', _('General'), 'basics', _('Basic Settings'))
예제 #59
0
파일: prefs.py 프로젝트: wataash/trac
 def get_preference_panels(self, req):
     yield ('notification', _('Notifications'))
예제 #60
0
파일: console.py 프로젝트: zxfly/trac
    def do_initenv(self, line):
        def initenv_error(msg):
            printerr(_("Initenv for '%(env)s' failed.", env=self.envname),
                     "\n%s" % msg)
        if self.env_check():
            initenv_error(_("Does an environment already exist?"))
            return 2

        arg = self.arg_tokenize(line)
        inherit_paths = []
        config_file_path = None
        i = 0
        while i < len(arg):
            item = arg[i]
            if item.startswith('--inherit='):
                inherit_paths.append(arg.pop(i)[10:])
            elif item.startswith('--config='):
                config_file_path = arg.pop(i)[9:]
            else:
                i += 1
        config = None
        if config_file_path:
            if not os.path.exists(config_file_path):
                initenv_error(_("The file specified in the --config argument "
                                "does not exist: %(path)s.",
                                path=config_file_path))
                return 2
            try:
                config = Configuration(config_file_path)
            except TracError as e:
                initenv_error(e)
                return 2
        arg = arg or ['']  # Reset to usual empty in case we popped the only one
        if len(arg) == 1 and not arg[0] and not config:
            project_name, db_str = self.get_initenv_args()
        elif len(arg) < 2 and config:
            project_name = db_str = None
            if arg[0]:
                project_name = arg[0]
        elif len(arg) == 2:
            project_name, db_str = arg
        else:
            initenv_error('Wrong number of arguments: %d' % len(arg))
            return 2

        options = []
        if config:
            for section in config.sections(defaults=False):
                options.extend((section, option, value)
                               for option, value
                               in config.options(section))
        if project_name is not None:
            options.append(('project', 'name', project_name))
        if db_str is not None:
            options.append(('trac', 'database', db_str))

        if inherit_paths:
            options.append(('inherit', 'file',
                            ",\n      ".join(inherit_paths)))

        printout(_("Creating and Initializing Project"))
        try:
            self.__env = Environment(self.envname, create=True,
                                     options=options)
        except TracError as e:
            initenv_error(e)
            return 2
        except Exception as e:
            initenv_error(_('Failed to create environment.'))
            printerr(e)
            traceback.print_exc()
            sys.exit(1)

        printout(_("""
---------------------------------------------------------------------
Project environment for '%(project_name)s' created.

You may now configure the environment by editing the file:

  %(config_path)s

If you'd like to take this new project environment for a test drive,
try running the Trac standalone web server `tracd`:

  tracd --port 8000 %(project_path)s

Then point your browser to http://localhost:8000/%(project_dir)s.
There you can also browse the documentation for your installed
version of Trac, including information on further setup (such as
deploying Trac to a real web server).

The latest documentation can also always be found on the project
website:

  http://trac.edgewall.org/

Congratulations!
""", project_name=project_name, project_path=self.envname,
           project_dir=os.path.basename(self.envname),
           config_path=self.__env.config_file_path))