Example #1
0
 def _has_edit_perm(self,pagename,username,req):
     perm_obj=PermissionSystem(self.env)
     user_permissions=perm_obj.get_user_permissions(username)
     perm_list=[]
     for i in user_permissions:
         if user_permissions[i]==True:
             perm_list.append(i)
     if "WIKI_MODIFY" in perm_list:
         if self._is_the_creator(pagename,username,req)==True:
             return True
         if "TRAC_ADMIN" in perm_list:
             return True
         else:
             cnx=self.env.get_db_cnx()
             cur=cnx.cursor()
             cur.execute("select count() from wiki_permission where pagename=\"%s\";"%(pagename,))
             exist=cur.fetchone()
             if exist[0] == 0:
                 cur.close()
                 cnx.commit()
                 cnx.close()
                 return True 
             cur.execute("select perm_w from wiki_permission where pagename=\"%s\" and username=\"%s\";"%(pagename,username))
             perm=cur.fetchone()
             cur.close()
             cnx.commit()
             cnx.close()
             if perm and perm[0]==1:
                 return True
             return False
     return False
Example #2
0
    def handle_edit_locale_admins(self, req, locale_id):
        if not locale_id:
            req.redirect(req.href.admin('translations', 'locales'))

        Session = session(self.env)
        locale = Session.query(Locale).get(int(locale_id))
        known_users = self.env.get_known_users()
        errors = []
        perm = PermissionSystem(self.env)
        sids_without_necessary_perms = []
        for admin in locale.admins:
            if not 'L10N_MODERATE' in perm.get_user_permissions(admin.sid):
                sids_without_necessary_perms.append(admin.sid)

        if sids_without_necessary_perms:
            msg = ngettext(
                "%s does not have the required permissions to administrate." % \
                ', '.join(["'%s'" % s for s in sids_without_necessary_perms]),
                "%s don't have the required permissions to administrate." % \
                ', '.join(["'%s'" % s for s in sids_without_necessary_perms]),
                 len(sids_without_necessary_perms))
            errors.append(
                tag(msg, _(" Don't forget to "),
                    tag.a(_('update permissions'),
                          href=req.href.admin('general', 'perm')), '.'))

        if req.method == 'POST' and len(req.args.getlist('admins')) >= 1:
            current_admins = req.args.getlist('current_admins')
            selected = req.args.getlist('admins')

            self.log.debug('Current Admins: %s', current_admins)
            self.log.debug('Selected Admins: %s', selected)

            allow_delete_admins = len(selected) >= 1
            if not allow_delete_admins:
                errors.append(
                    tag(_("There must be at least on admin for each locale.")))

            for admin in current_admins:
                if not allow_delete_admins:
                    break
                if admin not in selected:
                    locale_admin = Session.query(LocaleAdmin). \
                        filter(locale_admin_table.c.sid==admin).first()
                    Session.delete(locale_admin)
            for admin in selected:
                if admin not in locale.admins:
                    locale.admins.append(LocaleAdmin(locale, admin))
            Session.commit()
            req.redirect(req.href.admin('translations', 'locales'))
        elif req.method == 'POST' and len(req.args.getlist('admins')) < 1:
            errors.append(
                tag(_("There must be at least on admin for each locale.")))

        data = {'locale': locale, 'known_users': known_users}
        if errors:
            data['error'] = tag.ul(*[tag.li(e) for e in errors if e])

        return 'l10n_admin_locale_admins.html', data
Example #3
0
 def permissions(self):
     """Deprecated (but still used by the HDF compatibility layer)
     """
     self.perm.env.log.warning("perm.permissions() is deprecated and "
                          "is only present for HDF compatibility")
     permsys = PermissionSystem(self.perm.env)
     actions = permsys.get_user_permissions(self.perm.username)
     return [action for action in actions if action in self]
Example #4
0
 def permissions(self):
     """Deprecated (but still used by the HDF compatibility layer)
     """
     self.perm.env.log.warning("perm.permissions() is deprecated and "
                          "is only present for HDF compatibility")
     permsys = PermissionSystem(self.perm.env)
     actions = permsys.get_user_permissions(self.perm.username)
     return [action for action in actions if action in self]
Example #5
0
 def remove_permissions(self, permissions):
     perm = PermissionSystem(self.env)
     for agent, p in permissions.items():
         if '*' in p:
             p = [ i for i, j in perm.get_user_permissions(agent).items() if j]
         for permission in p:
             
             try:
                 perm.revoke_permission(agent, permission)
             except:
                 continue
Example #6
0
 def _has_permission(self, user, report_id):
     report_permissions = self._get_report_permissions(report_id)
     if not report_permissions:
         return True
     perms = PermissionSystem(self.env)
     report_permissions = set(report_permissions)
     user_perm = set(perms.get_user_permissions(user))
     groups = set(self._get_user_groups(user))
     user_perm.update(groups)
     if report_permissions.intersection(user_perm) != set([]):
         return True
     return False
Example #7
0
  def do_purge(self, req, path, users):
    """Purge obsolete data - i.e. environment data (sessions, preferences,
    permissions) from users no longer existing
    @param req
    @param path path to the trac env to purge
    @param users users to keep
    @return boolean success
    @return msg info
    """
    self.env.log.debug('+ Purging obsolete data')
    dryrun = self.env.config.getbool('user_sync','dryrun',True)
    sql = []
    envpath, tracenv = os.path.split(path)
    try:
      env = Environment(path)
    except IOError:
      self.env.log.debug('Could not initialize environment at %s' % (path,))
      return False, 'Could not initialize environment at %s' % (path,)
    perm = PermissionSystem(env)
    if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username):
      raise PermissionError
    excludes = self.get_perm_groups(path)+users
    protect = "'"+"','".join(excludes)+"'"
    self.env.log.debug("Excluding from purge: %s" % (protect,))
    db = env.get_db_cnx()
    cursor = db.cursor()
    if not dryrun:
      self.env.log.debug('Updating database for %s' % (tracenv,))
      cursor.execute('DELETE FROM auth_cookie WHERE name NOT IN (%s)' % (protect,))
      cursor.execute('DELETE FROM session WHERE sid NOT IN (%s)' % (protect,))
      cursor.execute('DELETE FROM session_attribute WHERE sid NOT IN (%s)' % (protect,))
      cursor.execute('DELETE FROM permission WHERE username NOT IN (%s)' % (protect,))
      db.commit()

    sql_file_path = self.env.config.get('user_sync','sql_file_path') or os.path.join(self.env.path,'log')
    if sql_file_path.lower() == 'none':
      self.env.log.debug('SQLFile disabled (sql_file_path is "none")')
    else:
      sqlfile = '%s.sql' % (tracenv,)
      sqlfile = os.path.join(sql_file_path,sqlfile)
      self.env.log.debug('Writing SQL to %s' % (sqlfile,))
      try:
          f = open(sqlfile,'a')
          f.write('\n--- SQL for purging Trac environment %s\n' % (tracenv,));
          f.write('DELETE FROM auth_cookie WHERE name NOT IN (%s);\n' % (protect,))
          f.write('DELETE FROM session WHERE sid NOT IN (%s);\n' % (protect,))
          f.write('DELETE FROM session_attribute WHERE sid NOT IN (%s);\n' % (protect,))
          f.write('DELETE FROM permission WHERE username NOT IN (%s);\n' % (protect,))
      except IOError:
          self.env.log.debug('Could not write SQL file %s!' % (sqlfile,))
          return False, 'Could not write SQL file %s!' % (sqlfile,)

    return True, 'Successfully purged environment %s' % (tracenv,)
Example #8
0
 def test_new_team_members_get_teammember_permissions(self):
     req = Mock(authname='admin', perm=MockPerm())
     new_member_name = 'fnord'
     
     admin_panel = TeamAdminPanel(self.env)
     team_member = ValueObject(dict(name=new_member_name))
     admin_panel.create_user_and_grant_permissions(req, team_member)
     
     permission_system = PermissionSystem(self.env)
     permissions = permission_system.get_user_permissions(new_member_name)
     self.assert_true(Role.TEAM_MEMBER in permissions)
     self.assert_true(permissions[Role.TEAM_MEMBER])
Example #9
0
 def _has_permission(self, user, report_id):
     report_permissions = self._get_report_permissions(report_id)
     if report_permissions == None or report_permissions == []:
         return True
     perms = PermissionSystem(self.env)
     report_permissions = set(report_permissions)
     user_perm = set(perms.get_user_permissions(user))
     groups = set(self._get_user_groups(user))
     user_perm.update(groups)
     if report_permissions.intersection(user_perm) != set([]):
         return True
     return False
Example #10
0
    def test_new_team_members_get_teammember_permissions(self):
        req = Mock(authname='admin', perm=MockPerm())
        new_member_name = 'fnord'

        admin_panel = TeamAdminPanel(self.env)
        team_member = ValueObject(dict(name=new_member_name))
        admin_panel.create_user_and_grant_permissions(req, team_member)

        permission_system = PermissionSystem(self.env)
        permissions = permission_system.get_user_permissions(new_member_name)
        self.assert_true(Role.TEAM_MEMBER in permissions)
        self.assert_true(permissions[Role.TEAM_MEMBER])
Example #11
0
    def remove_permissions(self, permissions):
        perm = PermissionSystem(self.env)
        for agent, p in permissions.items():
            if '*' in p:
                p = [
                    i for i, j in perm.get_user_permissions(agent).items() if j
                ]
            for permission in p:

                try:
                    perm.revoke_permission(agent, permission)
                except:
                    continue
Example #12
0
    def process_request(self, req):
        add_script(req, 'cc_selector/cc_selector.js')
        
        # fetch list of available developers:
        cc_developers = []
        db = self.env.get_db_cnx()
        perm = PermissionSystem(self.env)
        for username, name, email in self.env.get_known_users(db):
            if perm.get_user_permissions(username).get('TICKET_VIEW'):
                cc_developers.append(username)

        req.hdf['cc_developers'] = cc_developers
        return 'cc_selector.cs', None
Example #13
0
    def projects(self, user):
        base_path, _project = os.path.split(self.env.path)
        _projects = [p for p in os.listdir(base_path) if p != _project]
        projects = {}
        for project in _projects:
            path = os.path.join(base_path, project)
            try:
                env = open_environment(path, use_cache=True)
            except:
                continue
            perm = PermissionSystem(env)
            if self.permission in perm.get_user_permissions(user):
                projects[project] = env

        return projects
Example #14
0
    def projects(self, user):
        base_path, _project = os.path.split(self.env.path)
        _projects = [p for p in os.listdir(base_path) if p != _project]
        projects = {}
        for project in _projects:
            path = os.path.join(base_path, project)
            try:
                env = open_environment(path, use_cache=True)
            except:
                continue
            perm = PermissionSystem(env)
            if self.permission in perm.get_user_permissions(user):
                projects[project] = env

        return projects
Example #15
0
    def test_grant_undefined_permission_with_permission_grant(self):
        """Undefined permission is granted without checking granter."""
        ps = PermissionSystem(self.env)
        ps.grant_permission('user1', 'PERMISSION_GRANT')
        self.env.db_transaction("""
            INSERT INTO permission VALUES ('group1', 'TEST_PERM')
            """)
        req = MockRequest(self.env, method='POST', authname='user1', args={
            'add': True, 'subject': 'user2', 'group': 'group1'})

        with self.assertRaises(RequestDone):
            self.panel.render_admin_panel(req, 'general', 'perm', None)

        self.assertIn('TEST_PERM',
                      ps.get_user_permissions('group1', undefined=True))
        self.assertIn('user2', ps.get_groups_dict()['group1'])
Example #16
0
 def get_tracenv_userdata(self, req, path, userlist=''):
    """Retrieve account data from the environment at the specified path
    @param path path to the environment
    @param userlist comma separated list of users to restrict the result to (e.g. the users from the password file), each user enclosed in single quotes (for SQL)
    @return array (empty array if the environment uses a different password file than the master env calling us)
    """
    self.env.log.debug('Get user data from %s' % (path,))
    data = {}
    env = Environment(path)
    # if this environment uses a different password file, we return an empty dataset
    if self.env.config.get('account-manager','password_file') != env.config.get('account-manager','password_file'):
      self.env.log.info('Password files do not match, skipping environment %s' % (path,))
      return data
    perm = PermissionSystem(env)
    if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username):
      raise PermissionError
    db = env.get_db_cnx()
    cursor = db.cursor()
    sync_fields = self.env.config.getlist('user_sync','sync_fields')
    attr = "'"+"','".join(sync_fields)+"','email_verification_sent_to','email_verification_token'"
    self.env.log.debug('* Checking attributes: %s' % (attr,))
    if userlist:
      cursor.execute("SELECT sid,name,value FROM session_attribute WHERE sid IN (%s) AND name IN (%s)" % (userlist,attr,))
    else:
      cursor.execute("SELECT sid,name,value FROM session_attribute WHERE name IN (%s)" % (attr,))
    for row in cursor:
      if not row[0] in data: data[row[0]] = {}
      data[row[0]][row[1]] = row[2]
    for sid in data.iterkeys():
       no_data = True
       for att in sync_fields:
          if att in data[sid]:
             no_data = False
             break
       if no_data:
             self.env.log.debug('No data for %s in %s' % (sid,path,))
             data[sid] = Null
             continue
       data[sid]['path'] = path
       cursor.execute("SELECT authenticated FROM session_attribute WHERE sid='%s'" % (sid,))
       for row in cursor: data[sid]['authenticated'] = row[0]
       cursor.execute("SELECT datetime(last_visit,'unixepoch') AS last_visit FROM session WHERE sid='%s'" % (sid,))
       for row in cursor: data[sid]['last_visit'] = row[0]
    return data
Example #17
0
    def install(self):
        """Installer"""

        # Utility function to interpreted boolean option value
        getBool = lambda s: s.strip().lower() in ['true', 'yes']

        # Utility function to parse a multi-line/multi-value parameter
        def cleanMultiParams(v):
            params = [
                s.split('|') for s in [l.strip() for l in v.split('\n')]
                if len(s) > 0
            ]
            cleaned_params = []
            for line in params:
                cleaned_params.append([row.strip() for row in line])
            return cleaned_params

        # Utility function to transform any string to an ID
        getId = lambda s: ''.join([c for c in s if c.isalnum()]).lower()

        options = self.options

        # Add command line scripts trac-admin and tracd into bin
        entry_points = [('trac-admin', 'trac.admin.console', 'run'),
                        ('tracd', 'trac.web.standalone', 'main')]
        zc.buildout.easy_install.scripts(entry_points,
                                         pkg_resources.working_set,
                                         options['executable'],
                                         options['bin-directory'])

        ####################
        # Init Trac instance
        ####################

        # Generate the trac instance, if required
        location = options['location']
        project_name = options.get('project-name', 'My project')
        project_url = options.get('project-url', 'http://example.com')
        db = 'sqlite:%s' % os.path.join('db', 'trac.db')
        if not os.path.exists(location):
            os.mkdir(location)
        trac = TracAdmin(location)
        if not trac.env_check():
            trac.do_initenv('"%s" %s' % (project_name, db))
        env = trac.env

        # Remove Trac default example data
        clean_up = getBool(options.get('remove-examples', 'True'))
        if clean_up:
            # Remove default milestones
            for mil in Milestone.select(env):
                if mil.name in [
                        'milestone1', 'milestone2', 'milestone3', 'milestone4'
                ]:
                    mil.delete()
            # Remove default components
            for comp in Component.select(env):
                if comp.name in ['component1', 'component2']:
                    comp.delete()

        # Add custom milestones
        for mil_data in cleanMultiParams(options.get('milestones', '')):
            mil_name = mil_data[0]
            try:
                mil = Milestone(env, name=mil_name)
            except ResourceNotFound:
                mil = Milestone(env)
                mil.name = mil_name
                mil.insert()

        # Add custom components
        for comp_data in cleanMultiParams(options.get('components', '')):
            comp_name = comp_data[0]
            try:
                comp = Component(env, name=comp_name)
            except ResourceNotFound:
                comp = Component(env)
                comp.name = comp_name
                if len(comp_data) == 2 and comp_data[1] not in [None, '']:
                    comp.owner = comp_data[1]
                comp.insert()

        #######################
        # Generate the trac.ini
        #######################

        # Read the trac.ini config file
        trac_ini = os.path.join(location, 'conf', 'trac.ini')
        parser = ConfigParser.ConfigParser()
        parser.read([trac_ini])

        # Clean-up trac.ini: add missing stuff
        if 'components' not in parser.sections():
            parser.add_section('components')

        # Force upgrade of informations used during initialization
        parser.set('project', 'name', project_name)

        # Set all repositories
        repos = cleanMultiParams(options.get('repos', None))
        repo_names = [getId(r[0]) for r in repos]
        repo_types = {}.fromkeys([r[1].lower() for r in repos]).keys()
        if 'repositories' not in parser.sections():
            parser.add_section('repositories')
        for repo in repos:
            repo_name = getId(repo[0])
            repo_type = repo[1]
            repo_dir = repo[2]
            repo_url = repo[3]
            parser.set('repositories', '%s.type' % repo_name, repo_type)
            parser.set('repositories', '%s.dir' % repo_name, repo_dir)
            if repo_url not in ['', None]:
                parser.set('repositories', '%s.url' % repo_name, repo_url)

        # Set default repository
        default_repo = getId(options.get('default-repo', None))
        if default_repo and default_repo in repo_names:
            parser.set('repositories', '.alias', default_repo)
            parser.set('repositories', '.hidden', 'true')

        # Set repository sync method
        sync_method = options.get('repos-sync', 'request').strip().lower()
        svn_repos = [getId(r[0]) for r in repos if r[1] == 'svn']
        if sync_method == 'request':
            parser.set('trac', 'repository_sync_per_request',
                       ', '.join(svn_repos))
        # TODO
        # elif sync_method == 'hook':
        #   do stuff...

        # Set project description
        project_descr = options.get('project-description', None)
        if project_descr:
            parser.set('project', 'descr', project_descr)
            parser.set('header_logo', 'alt', project_descr)

        # Setup logo
        header_logo = options.get('header-logo', '')
        header_logo = os.path.realpath(header_logo)
        if os.path.exists(header_logo):
            shutil.copyfile(header_logo,
                            os.path.join(location, 'htdocs', 'logo'))
        parser.set('header_logo', 'src', 'site/logo')
        parser.set('header_logo', 'link', project_url)

        # Set footer message
        parser.set(
            'project', 'footer',
            options.get(
                'footer-message',
                'This Trac instance was generated by <a href="http://pypi.python.org/pypi/pbp.recipe.trac">pbp.recipe.trac</a>.'
            ))

        # SMTP parameters
        for name in ('always-bcc', 'always-cc', 'default-domain', 'enabled',
                     'from', 'from-name', 'password', 'port', 'replyto',
                     'server', 'subject-prefix', 'user'):
            param_name = "smtp-%s" % name
            default_value = None
            if param_name == "smtp-from-name":
                default_value = project_name
            value = options.get(param_name, default_value)
            if value is not None:
                parser.set('notification', param_name.replace('-', '_'), value)

        ###############
        # Plugins setup
        ###############

        # If one repository use Mercurial, hook its plugin
        if 'hg' in repo_types:
            parser.set('components', 'tracext.hg.*', 'enabled')

        # Configure the NavAdd plugin
        menu_items = cleanMultiParams(options.get('additional-menu-items', ''))
        item_list = []
        for item in menu_items:
            item_title = item[0]
            item_url = item[1]
            item_id = getId(item_title)
            item_list.append((item_id, item_title, item_url))
        if item_list > 0:
            parser.set('components', 'navadd.*', 'enabled')
            if 'navadd' not in parser.sections():
                parser.add_section('navadd')
            parser.set('navadd', 'add_items',
                       ','.join([i[0] for i in item_list]))
            for (uid, title, url) in item_list:
                parser.set('navadd', '%s.target' % uid, 'mainnav')
                parser.set('navadd', '%s.title' % uid, title)
                parser.set('navadd', '%s.url' % uid, url)

        # Enable and setup time tracking
        time_tracking = options.get('time-tracking-plugin',
                                    'disabled').strip().lower() == 'enabled'
        if time_tracking:
            parser.set('components', 'timingandestimationplugin.*', 'enabled')

        # Enable and setup the stat plugin
        stats = options.get('stats-plugin',
                            'disabled').strip().lower() == 'enabled'
        if stats:
            parser.set('components', 'tracstats.*', 'enabled')

        #######################
        # Final upgrades & sync
        #######################

        # Apply custom parameters defined by the user
        custom_params = cleanMultiParams(options.get('trac-ini-additional',
                                                     ''))
        for param in custom_params:
            if len(param) == 3:
                section = param[0]
                if section not in parser.sections():
                    parser.add_section(section)
                parser.set(section, param[1], param[2])

        # Write the final trac.ini
        parser.write(open(trac_ini, 'w'))

        # Reload the environment
        env.shutdown()
        trac = TracAdmin(location)
        env = trac.env

        # Set custom permissions
        perm_sys = PermissionSystem(env)
        for cperm in cleanMultiParams(options.get('permissions', '')):
            if len(cperm) == 2:
                user = cperm[0]
                current_user_perms = perm_sys.get_user_permissions(user)
                perm_list = [p.upper() for p in cperm[1].split(' ') if len(p)]
                for perm in perm_list:
                    if perm not in current_user_perms:
                        perm_sys.grant_permission(user, perm)

        # Upgrade Trac instance to keep it fresh
        needs_upgrade = env.needs_upgrade()
        force_upgrade = getBool(options.get('force-instance-upgrade', 'False'))
        if needs_upgrade or force_upgrade:
            env.upgrade(backup=True)

        # Force repository resync
        repo_resync = getBool(options.get('force-repos-resync', 'False'))
        if repo_resync:
            rm = RepositoryManager(env)
            repositories = rm.get_real_repositories()
            for repos in sorted(repositories, key=lambda r: r.reponame):
                repos.sync(clean=True)

        # Upgrade default wiki pages embedded in Trac instance
        wiki_upgrade = getBool(options.get('wiki-doc-upgrade', 'False'))
        if wiki_upgrade:
            # Got the command below from trac/admin/console.py
            pages_dir = pkg_resources.resource_filename(
                'trac.wiki', 'default-pages')
            WikiAdmin(env).load_pages(pages_dir,
                                      ignore=['WikiStart', 'checkwiki.py'],
                                      create_only=['InterMapTxt'])

        # Return files that were created by the recipe. The buildout
        # will remove all returned files upon reinstall.
        return tuple()
Example #18
0
    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()
            target = req.args.get('target', '').strip()
            action = req.args.get('action')
            group = req.args.get('group', '').strip()

            if subject and subject.isupper() or \
                    group and group.isupper() or \
                    target and target.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('admin', 'general/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('admin', 'general/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,
                            message=_("The subject %(subject)s was not added "
                                      "to the group %(group)s because the "
                                      "group has %(perm)s permission and "
                                      "users cannot grant permissions they "
                                      "don't possess.", subject=subject,
                                      group=group, perm=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))

            # Copy permissions to subject
            elif req.args.get('copy') and subject and target:
                req.perm.require('PERMISSION_GRANT')

                subject_permissions = [i[1] for i in all_permissions
                                            if i[0] == subject and
                                               i[1].isupper()]
                if not subject_permissions:
                    add_warning(req,_("The subject %(subject)s does not "
                                      "have any permissions.",
                                      subject=subject))

                for action in subject_permissions:
                    if (target, action) in all_permissions:
                        continue
                    if not action in all_actions: # plugin disabled?
                        self.env.log.warn("Skipped granting %s to %s: "
                                          "permission unavailable.",
                                          action, target)
                    else:
                        if action not in req.perm:
                            add_warning(req,
                                        _("The permission %(action)s was "
                                          "not granted to %(subject)s "
                                          "because users cannot grant "
                                          "permissions they don't possess.",
                                          action=action, subject=subject))
                            continue
                        perm.grant_permission(target, action)
                        add_notice(req, _("The subject %(subject)s has "
                                          "been granted the permission "
                                          "%(action)s.",
                                          subject=target, action=action))
                req.redirect(req.href.admin(cat, page))

            # Remove permissions action
            elif req.args.get('remove') and req.args.get('sel'):
                req.perm('admin', 'general/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))

        return 'admin_perms.html', {
            'actions': all_actions,
            'perms': perm.get_users_dict(),
            'groups': perm.get_groups_dict(),
            'unicode_to_base64': unicode_to_base64
        }
Example #19
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename not in ('ticket.html', 'ticket.rss'):
            return stream

        ticket_id = req.args.get('id')
        if not ticket_id:
            return stream

        # determine the username of the current user
        user = req.authname

        # determine if the user has the permission to see private comments
        perms = PermissionSystem(self.env)
        has_private_permission = \
            self.private_comment_permission in perms.get_user_permissions(user)

        # Remove private comments from Ticket Page
        if filename == 'ticket.html':
            buf = StreamBuffer()

            def check_comments():
                delimiter = '<div xmlns="http://www.w3.org/1999/xhtml" ' + \
                            'class="change" id="trac-change-'

                comment_stream = str(buf)
                # split the comment_stream to get single comments
                comments_raw = comment_stream.split(delimiter)
                comment_stream = ''

                for comment in comments_raw:
                    if comment is None or len(comment) < 1:
                        continue

                    # determine comment id
                    find = comment.find('">')
                    if find == -1:
                        continue
                    comment_id = comment[:find]

                    # concat the delimiter and the comment again
                    comment_code = delimiter + comment

                    # if the user has the permission to see the comment
                    # the comment_code will be appended to the comment_stream
                    comment_private = self._is_comment_private(
                        ticket_id, comment_id)

                    if comment_private:
                        comment_code = comment_code.replace(
                            '<span class="threading">',
                            '<span class="threading"> <span class="%s">'
                            'this comment is private</span>' %
                            str(self.css_class_private_comment_marker))

                    if has_private_permission or not comment_private:
                        comment_stream += comment_code

                return HTML(comment_stream)

            # filter all comments
            stream |= Transformer('//div[@class="change" and @id]') \
                .copy(buf).replace(check_comments)

            # if the user has the private comment permission the checkboxes
            # to change the private value will be added
            if has_private_permission:
                comment_box = tag.label(
                    _("Private Comment:"),
                    tag.input(type='checkbox', name='private_comment'))
                stream |= Transformer('//h2[@id="trac-add-comment"]') \
                    .after(comment_box)
                # Trac 1.0 and later:
                # stream |= Transformer(
                #   '//div[@id="trac-add-comment"]//fieldset').prepend(input)

        # Remove private comments from ticket RSS feed
        if filename == 'ticket.rss':
            comments = self._get_all_private_comments(ticket_id)

            self.log.debug("Private Comments for Ticket %d: %s" %
                           (ticket_id, comments))

            for comment_id in comments:
                stream |= Transformer('//item[%d]' % comment_id).remove()

        return stream
Example #20
0
class TestAgiloPermissions(AgiloTestCase):
    
    def setUp(self):
        self.super()
        self.env.config.set('trac', 'permission_policies', 'AgiloPolicy, DefaultPermissionPolicy, LegacyAttachmentPolicy')
        self.perm = PermissionSystem(self.env)
    
    def test_roles(self):
        self.teh.grant_permission('master', 'SCRUM_MASTER')
        self.teh.grant_permission('owner', 'PRODUCT_OWNER')
        
        # test if contains main and sub permission
        # for scrum master
        permissions = self.perm.get_user_permissions('master')
        self.assert_true('SCRUM_MASTER' in permissions)
        self.assert_true(Action.SAVE_REMAINING_TIME in permissions)
        
        # for product owner
        permissions = self.perm.get_user_permissions('owner')
        self.assert_true('PRODUCT_OWNER' in permissions)
        self.assert_true(Action.CREATE_STORY in permissions)
        self.assert_true(Action.CREATE_REQUIREMENT in permissions)
    
    def test_ticket_permissions(self):
        # create user with the necessary permission
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm_cache = PermissionCache(self.env, name_team_member)
        
        ticket = self.teh.create_ticket(Type.TASK)
        perm_cache(Realm.TICKET, ticket.id).assert_permission(Action.TICKET_EDIT)
        # a team member should be able to save the remaining time for unassigned
        # tickets
        perm_cache(Realm.TICKET, ticket.id).assert_permission(Action.SAVE_REMAINING_TIME)
        
        # Don't change the remaining time for tickets which belong to other 
        # team members
        ticket[Key.OWNER] = "Just another team member"
        ticket.save_changes("foo", "bar")
        
        new_perm_cache = PermissionCache(self.env, name_team_member)
        self.assert_raises(PermissionError,
                          new_perm_cache(Realm.TICKET, ticket.id).assert_permission, 
                          Action.SAVE_REMAINING_TIME)
    
    def test_edit_description_action_is_scoped_as_well(self):
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm = PermissionCache(self.env, name_team_member)
        requirement = self.teh.create_ticket(Type.REQUIREMENT)
        requirement_resource = requirement.resource
        self.assert_false(perm.has_permission(Action.TICKET_EDIT_DESCRIPTION, requirement_resource))
    
    def test_reporters_can_only_edit_unassigned_tickets(self):
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        ticket = self.teh.create_ticket(Type.TASK)
        ticket[Key.REPORTER] = name_team_member
        ticket[Key.OWNER] = None
        some_minutes_ago = now() - timedelta(minutes=2)
        ticket.save_changes("foo", "bar", when=some_minutes_ago)
        self.assert_equals(name_team_member, ticket[Key.REPORTER])
        self.assertNotEqual(name_team_member, ticket[Key.OWNER])
        
        perm_cache = PermissionCache(self.env, name_team_member)
        perm_cache(Realm.TICKET, ticket.id).assert_permission(Action.TICKET_EDIT)
        perm_cache(Realm.TICKET, ticket.id).assert_permission(Action.TICKET_EDIT_PAGE_ACCESS)
    
    def test_ticket_owner_or_resource_can_save_time(self):
        another_team_member = 'another team member'
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        self.teh.grant_permission(another_team_member, Role.TEAM_MEMBER)
        ticket = self.teh.create_ticket(Type.TASK, props={Key.OWNER: name_team_member,
                                                          Key.REMAINING_TIME: '12'})
        # Check that name_team_member can change remaining time
        new_perm_cache = PermissionCache(self.env, name_team_member)
        new_perm_cache(Realm.TICKET, ticket.id).assert_permission(Action.SAVE_REMAINING_TIME)
        
        # Check that another_team_member can't change remaining time
        self.assert_true(another_team_member not in ticket.get_resource_list(include_owner=True))
        new_perm_cache = PermissionCache(self.env, another_team_member)
        self.assert_raises(PermissionError,
                          new_perm_cache(Realm.TICKET, ticket.id).assert_permission, 
                          Action.SAVE_REMAINING_TIME)
    
    def test_all_users_in_resources_can_edit_ticket(self):
        ticket = self.teh.create_ticket(Type.TASK)
        ticket[Key.OWNER] = "Just another team member"
        ticket[Key.RESOURCES] = " foo, %s, bar " % name_team_member
        ticket.save_changes("foo", "bar")
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm_cache = PermissionCache(self.env, name_team_member)
        
        self.assertNotEqual(ticket[Key.OWNER], name_team_member)
        perm_cache(Realm.TICKET, ticket.id).assert_permission(Action.TICKET_EDIT)
    
    def test_attachement_permissions(self):
        # create user with the necessary permission
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        self.teh.grant_permission(name_product_owner, Role.PRODUCT_OWNER)
        
        ticket = self.teh.create_ticket(Type.REQUIREMENT)
        # None of the two users we use for testing must be the ticket's owner,
        # else they could always edit the ticket.
        ticket[Key.OWNER] = 'someone'
        ticket.save_changes('foo', 'we have to change the owner')
        
        # a product owner should be able to attach files to the ticket, but a 
        # team member must not
        po_perm_cache = PermissionCache(self.env, name_product_owner)
        self.assert_true(Action.ATTACHMENT_CREATE in po_perm_cache(Realm.TICKET, ticket.id))
        
        tm_perm_cache = PermissionCache(self.env, name_team_member)
        self.assert_raises(PermissionError,
            tm_perm_cache(Realm.TICKET, ticket.id).assert_permission, Action.ATTACHMENT_CREATE)
    
    def test_can_edit_ticket_if_he_can_create_referenced_tickets(self):
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm_cache = PermissionCache(self.env, name_team_member)
        
        story = self.teh.create_ticket(Type.USER_STORY)
        self.assert_true(perm_cache.has_permission(Action.TICKET_EDIT_PAGE_ACCESS, story.resource))
        self.assert_false(perm_cache.has_permission(Action.TICKET_EDIT, story.resource))
    
    # TODO: self.perm() as replacement for perm_cache...
    
    def _create_custom_ticket_type(self, type_name, field_names):
        custom_type = TicketType(self.env)
        custom_type.name = type_name
        custom_type.insert()
        
        config = AgiloConfig(self.env)
        config.change_option(type_name, field_names, section=AgiloConfig.AGILO_TYPES)
        config.reload()
        self.assert_true(type_name in config.get_available_types())
    
    def test_can_edit_ticket_for_custom_types(self):
        custom_type_name = 'MaintenanceTask'
        self._create_custom_ticket_type(custom_type_name, [Key.COMPONENT])
        permission_name = 'CREATE_' + custom_type_name.upper()
        self.teh.grant_permission(name_team_member, permission_name)
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        
        perm_cache = PermissionCache(self.env, name_team_member)
        ticket = self.teh.create_ticket(custom_type_name)
        self.assert_true(perm_cache.has_permission(Action.TICKET_EDIT, ticket.resource))
        self.assert_true(perm_cache.has_permission(Action.TICKET_EDIT_PAGE_ACCESS, ticket.resource))
    
    def test_team_members_can_edit_bugs(self):
        bug = self.teh.create_ticket(Type.BUG, {Key.SUMMARY: 'A bug'})
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        
        perm = PermissionCache(self.env, name_team_member)
        self.assert_true(perm.has_permission(Action.TICKET_EDIT, bug.resource))
Example #21
0
class TestAgiloPermissions(AgiloTestCase):
    def setUp(self):
        self.super()
        self.env.config.set(
            'trac', 'permission_policies',
            'AgiloPolicy, DefaultPermissionPolicy, LegacyAttachmentPolicy')
        self.perm = PermissionSystem(self.env)

    def test_roles(self):
        self.teh.grant_permission('master', 'SCRUM_MASTER')
        self.teh.grant_permission('owner', 'PRODUCT_OWNER')

        # test if contains main and sub permission
        # for scrum master
        permissions = self.perm.get_user_permissions('master')
        self.assert_true('SCRUM_MASTER' in permissions)
        self.assert_true(Action.SAVE_REMAINING_TIME in permissions)

        # for product owner
        permissions = self.perm.get_user_permissions('owner')
        self.assert_true('PRODUCT_OWNER' in permissions)
        self.assert_true(Action.CREATE_STORY in permissions)
        self.assert_true(Action.CREATE_REQUIREMENT in permissions)

    def test_ticket_permissions(self):
        # create user with the necessary permission
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm_cache = PermissionCache(self.env, name_team_member)

        ticket = self.teh.create_ticket(Type.TASK)
        perm_cache(Realm.TICKET,
                   ticket.id).assert_permission(Action.TICKET_EDIT)
        # a team member should be able to save the remaining time for unassigned
        # tickets
        perm_cache(Realm.TICKET,
                   ticket.id).assert_permission(Action.SAVE_REMAINING_TIME)

        # Don't change the remaining time for tickets which belong to other
        # team members
        ticket[Key.OWNER] = "Just another team member"
        ticket.save_changes("foo", "bar")

        new_perm_cache = PermissionCache(self.env, name_team_member)
        self.assert_raises(
            PermissionError,
            new_perm_cache(Realm.TICKET, ticket.id).assert_permission,
            Action.SAVE_REMAINING_TIME)

    def test_edit_description_action_is_scoped_as_well(self):
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm = PermissionCache(self.env, name_team_member)
        requirement = self.teh.create_ticket(Type.REQUIREMENT)
        requirement_resource = requirement.resource
        self.assert_false(
            perm.has_permission(Action.TICKET_EDIT_DESCRIPTION,
                                requirement_resource))

    def test_reporters_can_only_edit_unassigned_tickets(self):
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        ticket = self.teh.create_ticket(Type.TASK)
        ticket[Key.REPORTER] = name_team_member
        ticket[Key.OWNER] = None
        some_minutes_ago = now() - timedelta(minutes=2)
        ticket.save_changes("foo", "bar", when=some_minutes_ago)
        self.assert_equals(name_team_member, ticket[Key.REPORTER])
        self.assertNotEqual(name_team_member, ticket[Key.OWNER])

        perm_cache = PermissionCache(self.env, name_team_member)
        perm_cache(Realm.TICKET,
                   ticket.id).assert_permission(Action.TICKET_EDIT)
        perm_cache(Realm.TICKET,
                   ticket.id).assert_permission(Action.TICKET_EDIT_PAGE_ACCESS)

    def test_ticket_owner_or_resource_can_save_time(self):
        another_team_member = 'another team member'
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        self.teh.grant_permission(another_team_member, Role.TEAM_MEMBER)
        ticket = self.teh.create_ticket(Type.TASK,
                                        props={
                                            Key.OWNER: name_team_member,
                                            Key.REMAINING_TIME: '12'
                                        })
        # Check that name_team_member can change remaining time
        new_perm_cache = PermissionCache(self.env, name_team_member)
        new_perm_cache(Realm.TICKET,
                       ticket.id).assert_permission(Action.SAVE_REMAINING_TIME)

        # Check that another_team_member can't change remaining time
        self.assert_true(another_team_member not in ticket.get_resource_list(
            include_owner=True))
        new_perm_cache = PermissionCache(self.env, another_team_member)
        self.assert_raises(
            PermissionError,
            new_perm_cache(Realm.TICKET, ticket.id).assert_permission,
            Action.SAVE_REMAINING_TIME)

    def test_all_users_in_resources_can_edit_ticket(self):
        ticket = self.teh.create_ticket(Type.TASK)
        ticket[Key.OWNER] = "Just another team member"
        ticket[Key.RESOURCES] = " foo, %s, bar " % name_team_member
        ticket.save_changes("foo", "bar")
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm_cache = PermissionCache(self.env, name_team_member)

        self.assertNotEqual(ticket[Key.OWNER], name_team_member)
        perm_cache(Realm.TICKET,
                   ticket.id).assert_permission(Action.TICKET_EDIT)

    def test_attachement_permissions(self):
        # create user with the necessary permission
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        self.teh.grant_permission(name_product_owner, Role.PRODUCT_OWNER)

        ticket = self.teh.create_ticket(Type.REQUIREMENT)
        # None of the two users we use for testing must be the ticket's owner,
        # else they could always edit the ticket.
        ticket[Key.OWNER] = 'someone'
        ticket.save_changes('foo', 'we have to change the owner')

        # a product owner should be able to attach files to the ticket, but a
        # team member must not
        po_perm_cache = PermissionCache(self.env, name_product_owner)
        self.assert_true(
            Action.ATTACHMENT_CREATE in po_perm_cache(Realm.TICKET, ticket.id))

        tm_perm_cache = PermissionCache(self.env, name_team_member)
        self.assert_raises(
            PermissionError,
            tm_perm_cache(Realm.TICKET, ticket.id).assert_permission,
            Action.ATTACHMENT_CREATE)

    def test_can_edit_ticket_if_he_can_create_referenced_tickets(self):
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)
        perm_cache = PermissionCache(self.env, name_team_member)

        story = self.teh.create_ticket(Type.USER_STORY)
        self.assert_true(
            perm_cache.has_permission(Action.TICKET_EDIT_PAGE_ACCESS,
                                      story.resource))
        self.assert_false(
            perm_cache.has_permission(Action.TICKET_EDIT, story.resource))

    # TODO: self.perm() as replacement for perm_cache...

    def _create_custom_ticket_type(self, type_name, field_names):
        custom_type = TicketType(self.env)
        custom_type.name = type_name
        custom_type.insert()

        config = AgiloConfig(self.env)
        config.change_option(type_name,
                             field_names,
                             section=AgiloConfig.AGILO_TYPES)
        config.reload()
        self.assert_true(type_name in config.get_available_types())

    def test_can_edit_ticket_for_custom_types(self):
        custom_type_name = 'MaintenanceTask'
        self._create_custom_ticket_type(custom_type_name, [Key.COMPONENT])
        permission_name = 'CREATE_' + custom_type_name.upper()
        self.teh.grant_permission(name_team_member, permission_name)
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)

        perm_cache = PermissionCache(self.env, name_team_member)
        ticket = self.teh.create_ticket(custom_type_name)
        self.assert_true(
            perm_cache.has_permission(Action.TICKET_EDIT, ticket.resource))
        self.assert_true(
            perm_cache.has_permission(Action.TICKET_EDIT_PAGE_ACCESS,
                                      ticket.resource))

    def test_team_members_can_edit_bugs(self):
        bug = self.teh.create_ticket(Type.BUG, {Key.SUMMARY: 'A bug'})
        self.teh.grant_permission(name_team_member, Role.TEAM_MEMBER)

        perm = PermissionCache(self.env, name_team_member)
        self.assert_true(perm.has_permission(Action.TICKET_EDIT, bug.resource))
Example #22
0
 def update_tracenv_userdata(self, req, path, userdata):
   """Update the userdata in the specified environment using the records passed
   by userdata.
   @param path     : path to the trac environment to update
   @param userdata : collection of userdata as returned from merge()
   @return success : boolean
   @return msg     : details
   """
   sql = []
   exists = ''
   msg = ''
   envpath, tracenv = os.path.split(path)
   self.env.log.debug('Updating userdata in environment %s' % (path,))
   dryrun = self.env.config.getbool('user_sync','dryrun',True)
   if not dryrun:
     self.env.log.debug('HOT!!! We are NOT in dryrun mode!')
   else: self.env.log.debug('TESTING - we ARE in dryrun mode.')
   try:
     env = Environment(path)
   except IOError:
     self.env.log.debug('Could not initialize environment at %s' % (path,))
     return False, 'Could not initialize environment at %s' % (path,)
   perm = PermissionSystem(env)
   if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username):
     raise PermissionError
   db = env.get_db_cnx()
   cursor = db.cursor()
   if not dryrun: self.env.log.debug('Updating database for %s' % (tracenv,))
   for user in userdata:
     authenticated = userdata[user]['authenticated'] or 0
     for att in userdata[user]:
       if att in ['path','authenticated','last_visit']: continue
       cursor.execute("SELECT value FROM session_attribute WHERE sid='%s' AND name='%s' AND authenticated=%s" % (user,att,authenticated,))
       for row in cursor: exists = row[0]
       if exists:
         if exists == userdata[user][att]: continue
         if not dryrun: cursor.execute("UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n" % (userdata[user][att],user,att,authenticated,))
         sql.append("UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n" % (userdata[user][att],user,att,authenticated,))
       else:
         if not dryrun: cursor.execute("INSERT INTO session_attribute (sid,authenticated,name,value) VALUES('%s',%s,'%s','%s');\n" % (user,authenticated,att,userdata[user][att]))
         sql.append("INSERT INTO session_attribute (sid,authenticated,name,att) VALUES('%s',%s,'%s','%s');\n" % (user,authenticated,att,userdata[user][att]))
   if len(sql):
     if not dryrun: db.commit()
     sql_file_path = self.env.config.get('user_sync','sql_file_path') or os.path.join(self.env.path,'log')
     if sql_file_path.lower() == 'none':
       self.env.log.debug('SQLFile disabled (sql_file_path is "none")')
     else:
       sqlfile = '%s.sql' % (tracenv,)
       sqlfile = os.path.join(sql_file_path,sqlfile)
       try:
         if os.path.exists(sqlfile): os.unlink(sqlfile)
         self.env.log.debug('Writing SQL to %s' % (sqlfile,))
         f = open(sqlfile,'a')
         f.write('--- SQL for Trac environment %s\n' % (tracenv,));
         f.writelines(sql)
         f.close()
       except IOError:
         self.env.log.debug('Could not write SQL file %s!' % (sqlfile,))
         return False, 'Could not write SQL file %s!' % (sqlfile,)
       except ValueError:
         self.env.log.debug('No value for sqlfile?')
       if dryrun: msg = 'Wrote SQL for Trac environment %s to %s' % (tracenv,sqlfile,)
       else: msg = 'Updated userdata in environment %s. SQL was additionally written to %s' % (tracenv,sqlfile,)
   else:
     msg = 'No updates for Trac environment %s' % (tracenv)
   self.env.log.debug('Done updating userdata in environment %s' % (path,))
   return True, msg
Example #23
0
    def add_locale(self, req):
        data = {}
        errors = []
        catalog_template_id = req.args.get('catalog_template', None)
        locale = req.args.get('locale')
        locale_admins = req.args.getlist('admins')

        def add_error(error):
            errors.append(error)
            data['error'] = tag.ul(*[tag.li(e) for e in errors if e])
            data['locale'] = locale
            return data

        if not catalog_template_id:
            errors.append(_("You must first create a catalog template"))

        if not locale:
            return add_error(_("You must define the new catalog's locale"))
        if not locale_admins:
            return add_error(_("You must define at least one locale admin"))

        Session = session(self.env)
        catalog = Session.query(Catalog).get(catalog_template_id)

        num_plurals = get_plural(locale=locale).num_plurals

        _locale = Session.query(Locale).filter_by(locale=locale,
                                                  catalog_id=catalog.id).first()
        if _locale:
            data['locale'] = _locale
            return add_error(_("Locale Exists Already"))

        locale = Locale(catalog, locale, num_plurals)
        for sid in locale_admins:
            locale.admins.append(LocaleAdmin(locale, sid))

        catalog.locales.append(locale)

        Session.commit()

        perm = PermissionSystem(self.env)
        sids_without_necessary_perms = []
        for admin in locale.admins:
            if not 'L10N_MODERATE' in perm.get_user_permissions(admin.sid):
                sids_without_necessary_perms.append(admin.sid)

        if sids_without_necessary_perms:
            msg = ngettext(
                "%s does not have the required permissions to administrate." % \
                ', '.join(["'%s'" % s for s in sids_without_necessary_perms]),
                "%s don't have the required permissions to administrate." % \
                ', '.join(["'%s'" % s for s in sids_without_necessary_perms]),
                 len(sids_without_necessary_perms))
            add_error(tag(msg, _(" Don't forget to "),
                          tag.a(_('update permissions'),
                                href=req.href.admin('general', 'perm')),
                          '.'))

        add_notice(req, _("Locale added."))

        # Are we importing existing data
        locale_catalog_path = req.args.get('catalog')
        include_fuzzy = req.args.get('include_fuzzy') == '1'

        if not locale_catalog_path or locale_catalog_path == '/':
            return data

        repos = self.env.get_repository(req.authname)
        revision = repos.youngest_rev
        try:
            node = get_existing_node(req, repos, locale_catalog_path, revision)
        except NoSuchChangeset, e:
            raise ResourceNotFound(e.message, _('Invalid Changeset Number'))
Example #24
0
    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 = isinstance(sel, list) and sel or [sel]
                for key in sel:
                    subject, action = key.split(':', 1)
                    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))

        return 'admin_perms.html', {
            'actions': all_actions,
            'perms': all_permissions
        }
Example #25
0
 def update_tracenv_userdata(self, req, path, userdata):
     """Update the userdata in the specified environment using the records passed
 by userdata.
 @param path     : path to the trac environment to update
 @param userdata : collection of userdata as returned from merge()
 @return success : boolean
 @return msg     : details
 """
     sql = []
     exists = ''
     msg = ''
     envpath, tracenv = os.path.split(path)
     self.env.log.debug('Updating userdata in environment %s' % (path, ))
     dryrun = self.env.config.getbool('user_sync', 'dryrun', True)
     if not dryrun:
         self.env.log.debug('HOT!!! We are NOT in dryrun mode!')
     else:
         self.env.log.debug('TESTING - we ARE in dryrun mode.')
     try:
         env = Environment(path)
     except IOError:
         self.env.log.debug('Could not initialize environment at %s' %
                            (path, ))
         return False, 'Could not initialize environment at %s' % (path, )
     perm = PermissionSystem(env)
     if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username):
         raise PermissionError
     db = env.get_db_cnx()
     cursor = db.cursor()
     if not dryrun:
         self.env.log.debug('Updating database for %s' % (tracenv, ))
     for user in userdata:
         authenticated = userdata[user]['authenticated'] or 0
         for att in userdata[user]:
             if att in ['path', 'authenticated', 'last_visit']: continue
             cursor.execute(
                 "SELECT value FROM session_attribute WHERE sid='%s' AND name='%s' AND authenticated=%s"
                 % (
                     user,
                     att,
                     authenticated,
                 ))
             for row in cursor:
                 exists = row[0]
             if exists:
                 if exists == userdata[user][att]: continue
                 if not dryrun:
                     cursor.execute(
                         "UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n"
                         % (
                             userdata[user][att],
                             user,
                             att,
                             authenticated,
                         ))
                 sql.append(
                     "UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n"
                     % (
                         userdata[user][att],
                         user,
                         att,
                         authenticated,
                     ))
             else:
                 if not dryrun:
                     cursor.execute(
                         "INSERT INTO session_attribute (sid,authenticated,name,value) VALUES('%s',%s,'%s','%s');\n"
                         % (user, authenticated, att, userdata[user][att]))
                 sql.append(
                     "INSERT INTO session_attribute (sid,authenticated,name,att) VALUES('%s',%s,'%s','%s');\n"
                     % (user, authenticated, att, userdata[user][att]))
     if len(sql):
         if not dryrun: db.commit()
         sql_file_path = self.env.config.get(
             'user_sync', 'sql_file_path') or os.path.join(
                 self.env.path, 'log')
         if sql_file_path.lower() == 'none':
             self.env.log.debug(
                 'SQLFile disabled (sql_file_path is "none")')
         else:
             sqlfile = '%s.sql' % (tracenv, )
             sqlfile = os.path.join(sql_file_path, sqlfile)
             try:
                 if os.path.exists(sqlfile): os.unlink(sqlfile)
                 self.env.log.debug('Writing SQL to %s' % (sqlfile, ))
                 f = open(sqlfile, 'a')
                 f.write('--- SQL for Trac environment %s\n' % (tracenv, ))
                 f.writelines(sql)
                 f.close()
             except IOError:
                 self.env.log.debug('Could not write SQL file %s!' %
                                    (sqlfile, ))
                 return False, 'Could not write SQL file %s!' % (sqlfile, )
             except ValueError:
                 self.env.log.debug('No value for sqlfile?')
             if dryrun:
                 msg = 'Wrote SQL for Trac environment %s to %s' % (
                     tracenv,
                     sqlfile,
                 )
             else:
                 msg = 'Updated userdata in environment %s. SQL was additionally written to %s' % (
                     tracenv,
                     sqlfile,
                 )
     else:
         msg = 'No updates for Trac environment %s' % (tracenv)
     self.env.log.debug('Done updating userdata in environment %s' %
                        (path, ))
     return True, msg
Example #26
0
    def render_admin_panel(self, req, cat, page, path_info):
        perm = PermissionSystem(self.env)
        all_actions = perm.get_actions()

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

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

            # Grant permission to subject
            if 'add' in req.args and subject and action:
                req.perm('admin', 'general/perm').require('PERMISSION_GRANT')
                if action not in all_actions:
                    raise TracError(_("Unknown action"))
                req.perm.require(action)
                try:
                    perm.grant_permission(subject, action)
                except TracError as e:
                    add_warning(req, e)
                else:
                    add_notice(
                        req,
                        _(
                            "The subject %(subject)s has been "
                            "granted the permission %(action)s.",
                            subject=subject,
                            action=action))

            # Add subject to group
            elif 'add' in req.args and subject and group:
                req.perm('admin', 'general/perm').require('PERMISSION_GRANT')
                for action in perm.get_user_permissions(group):
                    req.perm.require(
                        action,
                        message=_(
                            "The subject %(subject)s was not added to "
                            "the group %(group)s because the group has "
                            "%(perm)s permission and users cannot grant "
                            "permissions they don't possess.",
                            subject=subject,
                            group=group,
                            perm=action))
                try:
                    perm.grant_permission(subject, group)
                except TracError as e:
                    add_warning(req, e)
                else:
                    add_notice(
                        req,
                        _(
                            "The subject %(subject)s has been "
                            "added to the group %(group)s.",
                            subject=subject,
                            group=group))

            # Copy permissions to subject
            elif 'copy' in req.args and subject and target:
                req.perm('admin', 'general/perm').require('PERMISSION_GRANT')

                subject_permissions = perm.get_users_dict().get(subject, [])
                if not subject_permissions:
                    add_warning(
                        req,
                        _(
                            "The subject %(subject)s does not "
                            "have any permissions.",
                            subject=subject))

                for action in subject_permissions:
                    if action not in all_actions:  # plugin disabled?
                        self.log.warning(
                            "Skipped granting %s to %s: "
                            "permission unavailable.", action, target)
                    else:
                        if action not in req.perm:
                            add_warning(
                                req,
                                _(
                                    "The permission %(action)s was "
                                    "not granted to %(subject)s "
                                    "because users cannot grant "
                                    "permissions they don't possess.",
                                    action=action,
                                    subject=subject))
                            continue
                        try:
                            perm.grant_permission(target, action)
                        except PermissionExistsError:
                            pass
                        else:
                            add_notice(
                                req,
                                _(
                                    "The subject %(subject)s has "
                                    "been granted the permission "
                                    "%(action)s.",
                                    subject=target,
                                    action=action))
                req.redirect(req.href.admin(cat, page))

            # Remove permissions action
            elif 'remove' in req.args and 'sel' in req.args:
                req.perm('admin', 'general/perm').require('PERMISSION_REVOKE')
                for key in req.args.getlist('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))

        return 'admin_perms.html', {
            'actions': all_actions,
            'allowed_actions': [a for a in all_actions if a in req.perm],
            'perms': perm.get_users_dict(),
            'groups': perm.get_groups_dict(),
            'unicode_to_base64': unicode_to_base64
        }
Example #27
0
    def install(self):
        """Installer"""

        # Utility function to interpreted boolean option value
        getBool = lambda s: s.strip().lower() in ['true', 'yes']

        # Utility function to parse a multi-line/multi-value parameter
        def cleanMultiParams(v):
            params = [s.split('|') for s in [l.strip() for l in v.split('\n')] if len(s) > 0]
            cleaned_params = []
            for line in params:
                cleaned_params.append([row.strip() for row in line])
            return cleaned_params

        # Utility function to transform any string to an ID
        getId = lambda s: ''.join([c for c in s if c.isalnum()]).lower()

        options = self.options

        #################
        # eggs from the config options
        ################

        requirements, ws = self.egg.working_set()
        
        for dist in pkg_resources.working_set:
            ws.add(dist)

        # Add command line scripts trac-admin and tracd into bin
        entry_points = [('trac-admin', 'trac.admin.console', 'run'),
                        ('tracd', 'trac.web.standalone', 'main')]
        zc.buildout.easy_install.scripts(
                entry_points, ws,
                options['executable'], options['bin-directory']
                )


        ####################
        # Init Trac instance
        ####################

        # Generate the trac instance, if required
        location = options['location']
        project_name = options.get('project-name', 'My project')
        project_url = options.get('project-url', 'http://example.com')
        db = 'sqlite:%s' % os.path.join('db', 'trac.db')
        if not os.path.exists(location):
            os.mkdir(location)
        trac = TracAdmin(location)
        if not trac.env_check():
            trac.do_initenv('"%s" %s' % (project_name, db))
        env = trac.env

        # Remove Trac default example data
        clean_up = getBool(options.get('remove-examples', 'True'))
        if clean_up:
            # Remove default milestones
            for mil in Milestone.select(env):
                if mil.name in ['milestone1', 'milestone2', 'milestone3', 'milestone4']:
                    mil.delete()
            # Remove default components
            for comp in Component.select(env):
                if comp.name in ['component1', 'component2']:
                    comp.delete()

        # Add custom milestones
        for mil_data in cleanMultiParams(options.get('milestones', '')):
            mil_name = mil_data[0]
            try:
                mil = Milestone(env, name=mil_name)
            except ResourceNotFound:
                mil = Milestone(env)
                mil.name = mil_name
                mil.insert()

        # Add custom components
        for comp_data in cleanMultiParams(options.get('components', '')):
            comp_name = comp_data[0]
            try:
                comp = Component(env, name=comp_name)
            except ResourceNotFound:
                comp = Component(env)
                comp.name = comp_name
                if len(comp_data) == 2 and comp_data[1] not in [None, '']:
                    comp.owner = comp_data[1]
                comp.insert()


        #######################
        # Generate the trac.ini
        #######################

        # Read the trac.ini config file
        trac_ini = os.path.join(location, 'conf', 'trac.ini')
        parser = ConfigParser.ConfigParser()
        parser.read([trac_ini])

        # Clean-up trac.ini: add missing stuff
        if 'components' not in parser.sections():
            parser.add_section('components')

        # Force upgrade of informations used during initialization
        parser.set('project', 'name', project_name)

        # Set all repositories
        repos = cleanMultiParams(options.get('repos', None))
        repo_names = [getId(r[0]) for r in repos]
        repo_types = {}.fromkeys([r[1].lower() for r in repos]).keys()
        if 'repositories' not in parser.sections():
            parser.add_section('repositories')
        for repo in repos:
            repo_name = getId(repo[0])
            repo_type = repo[1]
            repo_dir  = repo[2]
            repo_url  = repo[3]
            parser.set('repositories', '%s.type' % repo_name, repo_type)
            parser.set('repositories', '%s.dir'  % repo_name, repo_dir)
            if repo_url not in ['', None]:
                parser.set('repositories', '%s.url'  % repo_name, repo_url)

        # Set default repository
        default_repo = getId(options.get('default-repo', None))
        if default_repo and default_repo in repo_names:
            parser.set('repositories', '.alias', default_repo)
            parser.set('repositories', '.hidden', 'true')

        # Set repository sync method
        sync_method = options.get('repos-sync', 'request').strip().lower()
        svn_repos = [getId(r[0]) for r in repos if r[1] == 'svn']
        if sync_method == 'request':
          parser.set('trac', 'repository_sync_per_request', ', '.join(svn_repos))
        # TODO
        # elif sync_method == 'hook':
        #   do stuff...

        # Set project description
        project_descr = options.get('project-description', None)
        if project_descr:
            parser.set('project', 'descr', project_descr)
            parser.set('header_logo', 'alt', project_descr)

        # Setup logo
        header_logo = options.get('header-logo', '')
        header_logo = os.path.realpath(header_logo)
        if os.path.exists(header_logo):
            shutil.copyfile(header_logo, os.path.join(location, 'htdocs', 'logo'))
        parser.set('header_logo', 'src', 'site/logo')
        parser.set('header_logo', 'link', project_url)

        # Set footer message
        parser.set('project', 'footer', options.get('footer-message', 'This Trac instance was generated by <a href="http://pypi.python.org/pypi/pbp.recipe.trac">pbp.recipe.trac</a>.'))

        # SMTP parameters
        for name in ('always-bcc', 'always-cc', 'default-domain', 'enabled',
                     'from', 'from-name', 'password', 'port', 'replyto',
                     'server', 'subject-prefix', 'user'):
            param_name = "smtp-%s" % name
            default_value = None
            if param_name == "smtp-from-name":
                default_value = project_name
            value = options.get(param_name, default_value)
            if value is not None:
                parser.set('notification', param_name.replace('-', '_'), value)


        ###############
        # Plugins setup
        ###############

        # If one repository use Mercurial, hook its plugin
        if 'hg' in repo_types:
            parser.set('components', 'tracext.hg.*', 'enabled')

        # Configure the NavAdd plugin
        menu_items = cleanMultiParams(options.get('additional-menu-items', ''))
        item_list = []
        for item in menu_items:
            item_title = item[0]
            item_url = item[1]
            item_id = getId(item_title)
            item_list.append((item_id, item_title, item_url))
        if item_list > 0:
            parser.set('components', 'navadd.*', 'enabled')
            if 'navadd' not in parser.sections():
                parser.add_section('navadd')
            parser.set('navadd', 'add_items', ','.join([i[0] for i in item_list]))
            for (uid, title, url) in item_list:
                parser.set('navadd', '%s.target' % uid, 'mainnav')
                parser.set('navadd', '%s.title'  % uid, title)
                parser.set('navadd', '%s.url'    % uid, url)

        # Enable and setup time tracking
        time_tracking = options.get('time-tracking-plugin', 'disabled').strip().lower() == 'enabled'
        if time_tracking:
            parser.set('components', 'timingandestimationplugin.*', 'enabled')

        # Enable and setup the stat plugin
        stats = options.get('stats-plugin', 'disabled').strip().lower() == 'enabled'
        if stats:
            parser.set('components', 'tracstats.*', 'enabled')


        #######################
        # Final upgrades & sync
        #######################

        # Apply custom parameters defined by the user
        custom_params = cleanMultiParams(options.get('trac-ini-additional', ''))
        for param in custom_params:
            if len(param) == 3:
                section = param[0]
                if section not in parser.sections():
                    parser.add_section(section)
                parser.set(section, param[1], param[2])

        # Write the final trac.ini
        parser.write(open(trac_ini, 'w'))

        # Reload the environment
        env.shutdown()
        trac = TracAdmin(location)
        env = trac.env

        # Set custom permissions
        perm_sys = PermissionSystem(env)
        for cperm in cleanMultiParams(options.get('permissions', '')):
            if len(cperm) == 2:
                user = cperm[0]
                current_user_perms = perm_sys.get_user_permissions(user)
                perm_list = [p.upper() for p in cperm[1].split(' ') if len(p)]
                for perm in perm_list:
                    if perm not in current_user_perms:
                        perm_sys.grant_permission(user, perm)

        # Upgrade Trac instance to keep it fresh
        needs_upgrade = env.needs_upgrade()
        force_upgrade = getBool(options.get('force-instance-upgrade', 'False'))
        if needs_upgrade or force_upgrade:
            env.upgrade(backup=True)

        # Force repository resync
        repo_resync = getBool(options.get('force-repos-resync', 'False'))
        if repo_resync:
            rm = RepositoryManager(env)
            repositories = rm.get_real_repositories()
            for repos in sorted(repositories, key=lambda r: r.reponame):
                repos.sync(clean=True)

        # Upgrade default wiki pages embedded in Trac instance
        wiki_upgrade = getBool(options.get('wiki-doc-upgrade', 'False'))
        if wiki_upgrade:
            # Got the command below from trac/admin/console.py
            pages_dir = pkg_resources.resource_filename('trac.wiki',
                                                        'default-pages')
            WikiAdmin(env).load_pages( pages_dir
                                     , ignore=['WikiStart', 'checkwiki.py']
                                     , create_only=['InterMapTxt']
                                     )

        # Return files that were created by the recipe. The buildout
        # will remove all returned files upon reinstall.
        return tuple()
Example #28
0
 def get_tracenv_userdata(self, req, path, userlist=''):
     """Retrieve account data from the environment at the specified path
  @param path path to the environment
  @param userlist comma separated list of users to restrict the result to (e.g. the users from the password file), each user enclosed in single quotes (for SQL)
  @return array (empty array if the environment uses a different password file than the master env calling us)
  """
     self.env.log.debug('Get user data from %s' % (path, ))
     data = {}
     env = Environment(path)
     # if this environment uses a different password file, we return an empty dataset
     if self.env.config.get('account-manager',
                            'password_file') != env.config.get(
                                'account-manager', 'password_file'):
         self.env.log.info(
             'Password files do not match, skipping environment %s' %
             (path, ))
         return data
     perm = PermissionSystem(env)
     if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username):
         raise PermissionError
     db = env.get_db_cnx()
     cursor = db.cursor()
     sync_fields = self.env.config.getlist('user_sync', 'sync_fields')
     attr = "'" + "','".join(
         sync_fields
     ) + "','email_verification_sent_to','email_verification_token'"
     self.env.log.debug('* Checking attributes: %s' % (attr, ))
     if userlist:
         cursor.execute(
             "SELECT sid,name,value FROM session_attribute WHERE sid IN (%s) AND name IN (%s)"
             % (
                 userlist,
                 attr,
             ))
     else:
         cursor.execute(
             "SELECT sid,name,value FROM session_attribute WHERE name IN (%s)"
             % (attr, ))
     for row in cursor:
         if not row[0] in data: data[row[0]] = {}
         data[row[0]][row[1]] = row[2]
     for sid in data.iterkeys():
         no_data = True
         for att in sync_fields:
             if att in data[sid]:
                 no_data = False
                 break
         if no_data:
             self.env.log.debug('No data for %s in %s' % (
                 sid,
                 path,
             ))
             data[sid] = Null
             continue
         data[sid]['path'] = path
         cursor.execute(
             "SELECT authenticated FROM session_attribute WHERE sid='%s'" %
             (sid, ))
         for row in cursor:
             data[sid]['authenticated'] = row[0]
         cursor.execute(
             "SELECT datetime(last_visit,'unixepoch') AS last_visit FROM session WHERE sid='%s'"
             % (sid, ))
         for row in cursor:
             data[sid]['last_visit'] = row[0]
     return data
Example #29
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename not in ('ticket.html', 'ticket.rss'):
            return stream

        ticket_id = req.args.get('id')
        if not ticket_id:
            return stream

        # determine the username of the current user
        user = req.authname

        # determine if the user has the permission to see private comments
        perms = PermissionSystem(self.env)
        has_private_permission = \
            self.private_comment_permission in perms.get_user_permissions(user)

        # Remove private comments from Ticket Page
        if filename == 'ticket.html':
            buf = StreamBuffer()

            def check_comments():
                delimiter = '<div xmlns="http://www.w3.org/1999/xhtml" ' + \
                            'class="change" id="trac-change-'

                comment_stream = str(buf)
                # split the comment_stream to get single comments
                comments_raw = comment_stream.split(delimiter)
                comment_stream = ''

                for comment in comments_raw:
                    if comment is None or len(comment) < 1:
                        continue

                    # determine comment id
                    find = comment.find('">')
                    if find == -1:
                        continue
                    comment_id = comment[:find]

                    # concat the delimiter and the comment again
                    comment_code = delimiter + comment

                    # if the user has the permission to see the comment
                    # the comment_code will be appended to the comment_stream
                    comment_private = self._is_comment_private(ticket_id,
                                                               comment_id)

                    if comment_private:
                        comment_code = comment_code.replace(
                            '<span class="threading">',
                            '<span class="threading"> <span class="%s">'
                            'this comment is private</span>'
                            % str(self.css_class_private_comment_marker)
                        )

                    if has_private_permission or not comment_private:
                        comment_stream += comment_code

                return HTML(comment_stream)

            # filter all comments
            stream |= Transformer('//div[@class="change" and @id]') \
                .copy(buf).replace(check_comments)

            # if the user has the private comment permission the checkboxes
            # to change the private value will be added
            if has_private_permission:
                comment_box = tag.label(_("Private Comment:"),
                                        tag.input(type='checkbox',
                                                  name='private_comment'))
                stream |= Transformer('//h2[@id="trac-add-comment"]') \
                    .after(comment_box)
                # Trac 1.0 and later:
                # stream |= Transformer(
                #   '//div[@id="trac-add-comment"]//fieldset').prepend(input)

        # Remove private comments from ticket RSS feed
        if filename == 'ticket.rss':
            comments = self._get_all_private_comments(ticket_id)

            self.log.debug("Private Comments for Ticket %d: %s"
                           % (ticket_id, comments))

            for comment_id in comments:
                stream |= Transformer('//item[%d]' % comment_id).remove()

        return stream
Example #30
0
    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
        }
Example #31
0
    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()
            target = req.args.get('target', '').strip()
            action = req.args.get('action')
            group = req.args.get('group', '').strip()

            if subject and subject.isupper() or \
                    group and group.isupper() or \
                    target and target.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('admin', 'general/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('admin', 'general/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,
                            message=_(
                                "The subject %(subject)s was not added "
                                "to the group %(group)s because the "
                                "group has %(perm)s permission and "
                                "users cannot grant permissions they "
                                "don't possess.",
                                subject=subject,
                                group=group,
                                perm=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))

            # Copy permissions to subject
            elif req.args.get('copy') and subject and target:
                req.perm.require('PERMISSION_GRANT')

                subject_permissions = [
                    i[1] for i in all_permissions
                    if i[0] == subject and i[1].isupper()
                ]
                if not subject_permissions:
                    add_warning(
                        req,
                        _(
                            "The subject %(subject)s does not "
                            "have any permissions.",
                            subject=subject))

                for action in subject_permissions:
                    if (target, action) in all_permissions:
                        continue
                    if not action in all_actions:  # plugin disabled?
                        self.env.log.warn(
                            "Skipped granting %s to %s: "
                            "permission unavailable.", action, target)
                    else:
                        if action not in req.perm:
                            add_warning(
                                req,
                                _(
                                    "The permission %(action)s was "
                                    "not granted to %(subject)s "
                                    "because users cannot grant "
                                    "permissions they don't possess.",
                                    action=action,
                                    subject=subject))
                            continue
                        perm.grant_permission(target, action)
                        add_notice(
                            req,
                            _(
                                "The subject %(subject)s has "
                                "been granted the permission "
                                "%(action)s.",
                                subject=target,
                                action=action))
                req.redirect(req.href.admin(cat, page))

            # Remove permissions action
            elif req.args.get('remove') and req.args.get('sel'):
                req.perm('admin', 'general/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
        }
Example #32
0
    def get_ticket_fields(self):
        """Returns the list of fields available for tickets."""
        from trac.ticket import model

        db = self.env.get_db_cnx()
        fields = []

        # Basic text fields
        for name in ('summary', 'reporter'):
            field = {'name': name, 'type': 'text', 'label': name.title()}
            fields.append(field)

        # Owner field, can be text or drop-down depending on configuration
        field = {'name': 'owner', 'label': 'Owner'}
        if self.restrict_owner:
            field['type'] = 'select'
            users = []
            perm = PermissionSystem(self.env)
            for username, name, email in self.env.get_known_users(db):
                if perm.get_user_permissions(username).get('TICKET_MODIFY'):
                    users.append(username)
            field['options'] = users
            field['optional'] = True
        else:
            field['type'] = 'text'
        fields.append(field)

        # Description
        fields.append({'name': 'description', 'type': 'textarea',
                       'label': 'Description'})

        # Default select and radio fields
        selects = [('type', model.Type), ('status', model.Status),
                   ('priority', model.Priority), ('milestone', model.Milestone),
                   ('component', model.Component), ('version', model.Version),
                   ('severity', model.Severity), ('resolution', model.Resolution)]
        for name, cls in selects:
            options = [val.name for val in cls.select(self.env, db=db)]
            if not options:
                # Fields without possible values are treated as if they didn't
                # exist
                continue
            field = {'name': name, 'type': 'select', 'label': name.title(),
                     'value': self.config.get('ticket', 'default_' + name),
                     'options': options}
            if name in ('status', 'resolution'):
                field['type'] = 'radio'
                field['optional'] = True
            elif name in ('milestone', 'version'):
                field['optional'] = True
            fields.append(field)

        # Advanced text fields
        for name in ('keywords', 'cc', ):
            field = {'name': name, 'type': 'text', 'label': name.title()}
            fields.append(field)

        for field in self.get_custom_fields():
            if field['name'] in [f['name'] for f in fields]:
                self.log.warning('Duplicate field name "%s" (ignoring)',
                                 field['name'])
                continue
            if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', field['name']):
                self.log.warning('Invalid name for custom field: "%s" '
                                 '(ignoring)', field['name'])
                continue
            field['custom'] = True
            fields.append(field)

        return fields
Example #33
0
    def invoke(self, message, warnings):
        """reply to a ticket"""
        ticket = self.ticket
        reporter = self._reporter(message)
        # get the mailBody and attachments
        mailBody, attachments = get_body_and_attachments(message)
        if not mailBody:
            warnings.append("Seems to be a reply to %s but I couldn't find a comment")
            return message

        #go throught work

        ts = TicketSystem(self.env)
        tm = TicketModule(self.env)
        perm = PermissionSystem(self.env)
        # TODO: Deprecate update without time_changed timestamp
        mockReq = self._MockReq(perm.get_user_permissions(reporter), reporter)
        avail_actions = ts.get_available_actions(mockReq, ticket)

        mailBody, inBodyFields, actions = self._get_in_body_fields(mailBody, avail_actions, reporter)
        if inBodyFields or actions :
            # check permissions
            perm = PermissionSystem(self.env)
            #we have properties movement, cheking user permission to do so
            if not perm.check_permission('MAIL2TICKET_PROPERTIES', reporter) : # None -> 'anoymous'
                raise ("%s does not have MAIL2TICKET_PROPERTIES permissions" % (user or 'anonymous'))

        action = None
        if actions :
            action = actions.keys()[0] 
        controllers = list(tm._get_action_controllers(mockReq, ticket, action))
        all_fields = [field['name'] for field in ts.get_ticket_fields()]


        #impact changes find in inBodyFields
        for field in inBodyFields :
            ticket._old[field] = ticket[field]
            ticket.values[field] = inBodyFields[field]
            mockReq.args[field] = inBodyFields[field]
        if action : 
            mockReq.args['action_%s_reassign_owner' % action] = ticket['owner']



        mockReq.args['comment'] = mailBody
        mockReq.args['ts'] = datetime.now()#to_datetime(None, utc)


        mockReq.args['ts'] = str(ticket.time_changed)
        
        changes, problems = tm.get_ticket_changes(mockReq, ticket, action)
        valid = problems and False or tm._validate_ticket(mockReq, ticket)

        tm._apply_ticket_changes(ticket, changes)


        # add attachments to the ticket
        add_attachments(self.env, ticket, attachments)

        ticket.save_changes(reporter, mailBody)
        
        for controller in controllers:
            controller.apply_action_side_effects(mockReq, ticket, action)
            # Call ticket change listeners
        for listener in ts.change_listeners:
            listener.ticket_changed(ticket, mailBody, reporter, ticket._old)

        tn = TicketNotifyEmail(self.env)
        tn.notify(ticket, newticket=0, modtime=ticket.time_changed)
Example #34
0
    def get_ticket_fields(self):
        """Returns the list of fields available for tickets."""
        from trac.ticket import model

        db = self.env.get_db_cnx()
        fields = []

        # Basic text fields
        for name in ('summary', 'reporter'):
            field = {'name': name, 'type': 'text', 'label': name.title()}
            fields.append(field)

        # Owner field, can be text or drop-down depending on configuration
        field = {'name': 'owner', 'label': 'Owner'}
        if self.restrict_owner:
            field['type'] = 'select'
            users = []
            perm = PermissionSystem(self.env)
            for username, name, email in self.env.get_known_users(db):
                if perm.get_user_permissions(username).get('TICKET_MODIFY'):
                    users.append(username)
            field['options'] = users
            field['optional'] = True
        else:
            field['type'] = 'text'
        fields.append(field)

        # Description
        fields.append({
            'name': 'description',
            'type': 'textarea',
            'label': 'Description'
        })

        # Default select and radio fields
        selects = [('type', model.Type), ('status', model.Status),
                   ('priority', model.Priority),
                   ('milestone', model.Milestone),
                   ('component', model.Component), ('version', model.Version),
                   ('severity', model.Severity),
                   ('resolution', model.Resolution)]
        for name, cls in selects:
            options = [val.name for val in cls.select(self.env, db=db)]
            if not options:
                # Fields without possible values are treated as if they didn't
                # exist
                continue
            field = {
                'name': name,
                'type': 'select',
                'label': name.title(),
                'value': self.config.get('ticket', 'default_' + name),
                'options': options
            }
            if name in ('status', 'resolution'):
                field['type'] = 'radio'
                field['optional'] = True
            elif name in ('milestone', 'version'):
                field['optional'] = True
            fields.append(field)

        # Advanced text fields
        for name in (
                'keywords',
                'cc',
        ):
            field = {'name': name, 'type': 'text', 'label': name.title()}
            fields.append(field)

        for field in self.get_custom_fields():
            if field['name'] in [f['name'] for f in fields]:
                self.log.warning('Duplicate field name "%s" (ignoring)',
                                 field['name'])
                continue
            if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', field['name']):
                self.log.warning(
                    'Invalid name for custom field: "%s" '
                    '(ignoring)', field['name'])
                continue
            field['custom'] = True
            fields.append(field)

        return fields
Example #35
0
    def get_ticket_fields(self):
        """Returns the list of fields available for tickets."""
        from trac.ticket import model

        db = self.env.get_db_cnx()
        fields = []

        # Basic text fields
        for name in ("summary", "reporter"):
            field = {"name": name, "type": "text", "label": name.title()}
            fields.append(field)

        # Owner field, can be text or drop-down depending on configuration
        field = {"name": "owner", "label": "Owner"}
        if self.restrict_owner:
            field["type"] = "select"
            users = []
            perm = PermissionSystem(self.env)
            for username, name, email in self.env.get_known_users(db):
                if perm.get_user_permissions(username).get("TICKET_MODIFY"):
                    users.append(username)
            field["options"] = users
            field["optional"] = True
        else:
            field["type"] = "text"
        fields.append(field)

        # Description
        fields.append({"name": "description", "type": "textarea", "label": "Description"})

        # Default select and radio fields
        selects = [
            ("type", model.Type),
            ("status", model.Status),
            ("priority", model.Priority),
            ("milestone", model.Milestone),
            ("component", model.Component),
            ("version", model.Version),
            ("severity", model.Severity),
            ("resolution", model.Resolution),
        ]
        for name, cls in selects:
            options = [val.name for val in cls.select(self.env, db=db)]
            if not options:
                # Fields without possible values are treated as if they didn't
                # exist
                continue
            field = {
                "name": name,
                "type": "select",
                "label": translate(self.env, name, True),
                "value": self.config.get("ticket", "default_" + name),
                "options": options,
            }
            if name in ("status", "resolution"):
                field["type"] = "radio"
                field["optional"] = True
            elif name in ("milestone", "version"):
                field["optional"] = True
            fields.append(field)

        # Advanced text fields
        for name in ("keywords", "cc"):
            field = {"name": name, "type": "text", "label": translate(self.env, name, True)}
            fields.append(field)

        for field in self.get_custom_fields():
            if field["name"] in [f["name"] for f in fields]:
                self.log.warning('Duplicate field name "%s" (ignoring)', field["name"])
                continue
            if not re.match("^[a-zA-Z][a-zA-Z0-9_]+$", field["name"]):
                self.log.warning('Invalid name for custom field: "%s" ' "(ignoring)", field["name"])
                continue
            field["custom"] = True
            fields.append(field)

        return fields