Example #1
0
    def remove_user_from_group(self, user_name, group_name):
        """
        Removes user from group.

        :param str user_name: User name
        :param str group_name: Group name
        :raises InvalidPermissionState: User cannot be removed
        :raises DatabaseError: Query failure
        :raises ValueError: User not found
        """

        userstore = get_userstore()
        user = userstore.getUser(user_name)

        if not user:
            raise InvalidPermissionsState('Unknown user %s' % user_name)

        # Get the group
        group_name = group_name.encode('utf-8')
        group_id = self.get_group_id(group_name)
        if group_id is None:
            conf.log.exception("Group %s doesn't exists'" % group_name)

        self._cache.clear_user_groups(self.trac_environment_key)

        with admin_query() as cursor:
            cursor.callproc("remove_user_from_group", [user.id, group_id])
Example #2
0
    def expand_macro(self, formatter, name, content, args=None):
        """
        Returns the outcome from macro.
        Supported arguments:

        - count: Number of entries to show

        """
        req = formatter.req
        papi = Projects()
        userstore = get_userstore()

        # Parse optional arguments
        if args is None:
            args = parse_args(content)
            if len(args) > 1:
                args = args[1]

        featured_projects = papi.get_projects_for_rss('FEATURED',
                                                      limit_count=args.get(
                                                          'count', 5))

        data = {'featured_projects': featured_projects}
        return Chrome(self.env).render_template(req,
                                                'multiproject_featured.html',
                                                data,
                                                fragment=True)
    def render_preference_panel(self, req, panel):
        """ Renders preference panel and handles information change on POST
        """
        if req.authname == 'anonymous':
            raise TracError("User is not authenticated", "No access")

        data = {}
        key_store = CQDESshKeyStore.instance()
        user = get_userstore().getUser(req.authname)

        if req.method == 'POST':
            ssh_key = req.args.get('ssh_key')
            delete_key = req.args.get('deletelist')

            if ssh_key:
                user = self._do_save(req, user)
            elif delete_key:
                user = self._do_deletes(req, user)
            else:
                add_warning(req, _('Please provide data'))

        keys = key_store.get_ssh_keys_by_user_id(user.id)
        data['keys'] = keys if keys else None

        # This is to prevent adding of more than one ssh password.
        # Remove this if we support more in the future.
        if keys:
            data['hide_add_dialog'] = False

        data['domain'] = conf.domain_name
        data['user'] = user

        return 'multiproject_user_prefs_ssh_keys.html', data
Example #4
0
    def _list_notifications(self, req):
        """
        Returns the list of missed notification and optionally reset them
        """
        chname = None
        initiator = req.args.get('initiator', '')
        reset = req.args.get('reset', 'false').lower() in ('yes', 'true', 'on', '1')
        ntype = req.args.get('type', '')

        # Check permissions
        if req.authname == 'anonymous':
            return send_json(req, {'result': 'Permission denied'}, status=403)

        userstore = get_userstore()
        user = userstore.getUser(req.authname)
        ns = self.env[NotificationSystem]
        if not ns:
            return send_json(req, [])

        # Fetch notifications sent to user
        chname = ns.generate_channel_name(user_id=user.id)

        # Get notifications
        try:
            notifications = ns.get_notifications(chname)
        except TracError, e:
            self.log.error('Failed to retrieve notifications')
            return send_json(req, {'result': e.message}, status=500)
Example #5
0
    def process_request(self, req):
        """ Render welcome page
        """

        # Prepare data for template
        prjs = Projects()
        data = {}
        data['baseurl'] = conf.url_projects_path
        if req.authname == 'anonymous':
            conf.redirect(req)

        # Get project count
        data['project_count'] = prjs.project_count()

        user = get_userstore().getUser(req.authname)
        global_timeline = GlobalTimeline()

        data['show_explore'] = self.env[FindProjectsModule].has_explore_perm(req)
        data['latest_events'] = global_timeline.get_latest_events(req.authname, 5)

        # Check if user is allowed to create project
        data['can_create_project'] = user.can_create_project()

        # Configuration values the welcome page wants
        data['site_name'] = conf.site_name
        data['site_title_text'] = conf.site_title_text
        data['site_punch_line'] = conf.punch_line
        data['site_theme_path'] = conf.getThemePath()

        wiki_welcome = self._get_welcome_page(req)
        if wiki_welcome:
            data['wiki_welcome'] = wiki_welcome

        return "welcome.html", data, None
    def changePassword(self, req):
        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        oldpw = req.args.get('oldpassword')
        newpw = req.args.get('newpassword')

        if not oldpw or not userstore.userExists(req.authname, oldpw):
            add_warning(req, _('Old password is invalid'))
            return user

        if not newpw or len(newpw) < 7:
            add_warning(req,
                        _('New password should be at least 7 characters long'))
            return user

        if newpw != req.args.get('confirmpw'):
            add_warning(req, _('Passwords do not match'))
            return user

        if not userstore.updatePassword(user, newpw):
            add_warning(req, _('Failed to change the password'))
            return user

        add_notice(req, _('Password changed'))
        return user
Example #7
0
    def changePassword(self, req):
        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        oldpw = req.args.get('oldpassword')
        newpw = req.args.get('newpassword')

        if not oldpw or not userstore.userExists(req.authname, oldpw):
            add_warning(req, _('Old password is invalid'))
            return user

        if not newpw or len(newpw) < 7:
            add_warning(req, _('New password should be at least 7 characters long'))
            return user

        if newpw != req.args.get('confirmpw'):
            add_warning(req, _('Passwords do not match'))
            return user

        if not userstore.updatePassword(user, newpw):
            add_warning(req, _('Failed to change the password'))
            return user

        add_notice(req, _('Password changed'))
        return user
Example #8
0
    def _do_save(self, req, user):
        """ Update user information into database
        """
        userstore = get_userstore()

        if not req.args.get('mail'):
            add_warning(req, _('User should have an e-mail address'))
            return user

        user.mail = req.args.get('mail')

        if not req.args.get('lastName'):
            add_warning(req, _('Last name required'))
            return user

        # NOTE: Values are escaped in userstore update
        user.lastName = req.args.get('lastName')
        user.givenName = req.args.get('givenName')
        user.mobile = req.args.get('mobile')

        if userstore.updateUser(user):
            user = userstore.getUser(user.username)
            add_notice(req, _('Updated user settings'))

            if req.args.get('approve') == 'on' and user.status == user.STATUS_INACTIVE:
                user.activate()
                add_notice(req, _("Your account is now activated."))

            return user

        add_warning(req, _('Failed to update user'))
        return user
Example #9
0
    def _select_login_action(self, req, remote_user):
        """
        Select login action based on user status.

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

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

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

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

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

        add_warning(req, _("User status is '%s'. Can not log in." % user_store.USER_STATUS_LABELS[user.status]))
        return self._show_login(req)
Example #10
0
    def _create_user(self, username):
        """
        Create new user using data available in LDAP service

        This method is used in two cases:
        - when the user is authenticated for the first time (by self.authenticate)
        - when the user, which doesn't yet exist in the local DB, is added to project group
          (by self.store_user_if_necessary)

        :param str username: Name of the user in LDAP
        :returns: username on success, otherwise None
        """
        users = get_userstore()
        ldap_store = get_authstore()

        # If user does not exists in LDAP, do not continue
        if not ldap_store.userExists(username):
            conf.log.debug('Cannot find user %s from LDAP' % username)
            return None

        # Create user using LDAP store
        user = ldap_store.getUser(username)
        user.authentication_key = self.ldap_authentication_key
        user.organization_keys = self.org_store.get_organization_keys(user, self.LDAP) or None

        # Store user in user store
        conf.log.info('Created new user from LDAP: %s' % user.username)
        users.storeUser(user)
        users.invalidate_user_password(user)

        return user.username
Example #11
0
    def render_admin_panel(self, req, category, page, path_info):
        """
        Process a request for an admin panel.

        :Returns: A tuple of the form `(template, data)`,
        """
        # Ensure the user has project admin permissions
        req.perm.assert_permission('TRAC_ADMIN')

        backups = []
        backup_href = Href('%s/admin/general/backup' % req.base_path)

        # Load the user based on authname
        user = get_userstore().getUser(req.authname)

        # Get the current environment name
        env_name = conf.resolveProjectName(self.env)

        # Initiate ProjectBackup, containing the backup/restore implementation
        prj = Project.get(env_name=env_name)
        pb = ProjectBackup(prj)
        backups = pb.get_backups()

        # Do the backup
        if req.path_info.endswith('backup/backup') and req.method == 'POST':
            try:
                pb.backup(user_id=user.id, description=req.args.get('description'))
                add_notice(req, _('Backup created'))
            except TracError, e:
                add_warning(req, _('Backup failed: %s' % e))

            # Return back to default backup page
            return req.redirect(backup_href())
Example #12
0
    def render_preference_panel(self, req, panel):
        """ Renders preference panel and handles information change on POST
        """
        if req.authname == 'anonymous':
            raise TracError("User is not authenticated", "No access")

        data = {}
        key_store = CQDESshKeyStore.instance()
        user = get_userstore().getUser(req.authname)

        if req.method == 'POST':
            ssh_key = req.args.get('ssh_key')
            delete_key = req.args.get('deletelist')

            if ssh_key:
                user = self._do_save(req, user)
            elif delete_key:
                user = self._do_deletes(req, user)
            else:
                add_warning(req, _('Please provide data'))

        keys = key_store.get_ssh_keys_by_user_id(user.id)
        data['keys'] = keys if keys else None

        # This is to prevent adding of more than one ssh password.
        # Remove this if we support more in the future.
        if keys:
            data['hide_add_dialog'] = False

        data['domain'] = conf.domain_name
        data['user'] = user

        return 'multiproject_user_prefs_ssh_keys.html', data
Example #13
0
    def process_request(self, req):
        req.perm.assert_permission('MESSAGE_VIEW')

        msgsrv = self.env[MessageService]
        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        message_groups = msgsrv.get_latest_message_groups(user.id, limit=15)

        # Fetch and set notifications if component is enabled
        # TODO: Move into MessageService?
        if self.env.is_component_enabled('multiproject.common.notifications.push.NotificationSystem'):
            from multiproject.common.notifications.push import NotificationSystem

            ns = self.env[NotificationSystem]
            chname = ns.generate_channel_name(user)

            try:
                # Update message objects to have notification count
                for message_group in message_groups:
                    message_keys = ['message-%s' % message.id for message in message_group.get_messages()]
                    message_group.notifications = ns.get_notifications(chname, message_keys)

            except TracError, e:
                self.log.error('Failed to retrieve notifications')
Example #14
0
    def expand_macro(self, formatter, name, content, args=None):
        """
        Returns the outcome from macro.
        Supported arguments:

        - count: Number of entries to show

        """
        req = formatter.req
        papi = Projects()
        userstore = get_userstore()
        projects = []

        # Parse optional arguments
        if args is None:
            args = parse_args(content)
            if len(args) > 1:
                args = args[1]

        projects = papi.get_projects_for_rss('MOSTACTIVE',
                                             limit_count=args.get('count', 5),
                                             limit_activity=self.min_activity)

        return Chrome(self.env).render_template(req,
                                                'multiproject_active.html',
                                                {'active_projects': projects},
                                                fragment=True)
Example #15
0
    def expand_macro(self, formatter, name, content, args=None):
        """
        Returns the outcome from macro.
        """
        req = formatter.req
        userstore = get_userstore()
        user = userstore.getUser(req.authname)
        msgsrv = self.env[MessageService]

        # Parse optional arguments
        if args is None:
            args = parse_args(content)
            if len(args) > 1:
                args = args[1]

        data = {
            'groups': msgsrv.get_messages_grouped_by(user.id)
        }

        # FIXME: Temporary fix for IE8 + jQuery 1.4.4 + Transparency combination
        agent = req.get_header('user-agent')
        if agent and 'MSIE 8.0' not in agent:
            add_script(req, 'multiproject/js/transparency.js')

        add_script(req, 'multiproject/js/multiproject.js')
        add_script(req, 'multiproject/js/messages_group_macro.js')

        chrome = Chrome(self.env)
        return chrome.render_template(req, 'multiproject_messages_group_macro.html', data, fragment=True)
Example #16
0
def _chrome_format_author_replacement(self, req, author):
    """
    Audit Chrome.format_author method so that we get link to user profile

    Downside: This is a hack that interfere with the way trac renders usernames.
              Will have some unwanted behaviour.

              One such known unwanted behaviour is in the ticket view where owner and
              reporter links are changed
    """
    if not author:
        return ""
    unwanted_users = [
        'trac', 'tracadmin', 'anonymous', 'authenticated', 'somebody'
    ]
    not_ticket = req.path_info.rsplit('/', 2)[1] != 'ticket'
    contain_email = bool(re.search('<.+>', author))
    ok_user = author not in unwanted_users
    username = author
    if not contain_email:
        user = get_userstore().getUser(author)
        if user:
            author = user.getDisplayName()
    elif not Chrome(self.env).show_email_addresses:
        author = obfuscate_email_address(author)

    # Create a link to profile page or return author in plain
    if ok_user and not_ticket and not contain_email and conf.public_user_page_url:
        return tag.a(
            author, **{
                'href': conf.public_user_page_url + username,
                'class': 'author'
            })
    else:
        return author
Example #17
0
 def get_preference_panels(self, req):
     """ Give name of the panel
     """
     user = get_userstore().getUser(req.authname)
     has_external_avatar = Authentication().has_external_profile(user)
     if req.authname != 'anonymous' and not has_external_avatar:
         yield ('image', 'Face image')
Example #18
0
    def authenticate(self, username, password):
        """ Check username and password - either from local database, LDAP,
            or some other external authentication server.
            Return username on success, None on failure.
        """
        if not username or not password:
            return None

        # old user
        user = get_userstore().getUser(username)
        if user:
            authentication_name = self.auth_store.get_authentication_method(
                user.authentication_key)
            auth_module = self._get_auth_module(authentication_name)
            if auth_module:
                auth_username = auth_module.authenticate(username, password)
                if auth_username:
                    User.update_last_login(auth_username)
                    return auth_username
            return None

        # new user
        for x in conf.authentication_order:
            auth_module = self._get_auth_module(x)
            if auth_module:
                auth_username = auth_module.authenticate(username, password)
                if auth_username:
                    User.update_last_login(auth_username)
                    return auth_username
        return None
Example #19
0
    def _create_user(self, username):
        """
        Create new user using data available in LDAP service

        This method is used in two cases:
        - when the user is authenticated for the first time (by self.authenticate)
        - when the user, which doesn't yet exist in the local DB, is added to project group
          (by self.store_user_if_necessary)

        :param str username: Name of the user in LDAP
        :returns: username on success, otherwise None
        """
        users = get_userstore()
        ldap_store = get_authstore()

        # If user does not exists in LDAP, do not continue
        if not ldap_store.userExists(username):
            conf.log.debug('Cannot find user %s from LDAP' % username)
            return None

        # Create user using LDAP store
        user = ldap_store.getUser(username)
        user.authentication_key = self.ldap_authentication_key
        user.organization_keys = self.org_store.get_organization_keys(
            user, self.LDAP) or None

        # Store user in user store
        conf.log.info('Created new user from LDAP: %s' % user.username)
        users.storeUser(user)
        users.invalidate_user_password(user)

        return user.username
Example #20
0
    def authenticate(self, username, password):
        """ Check username and password - either from local database, LDAP,
            or some other external authentication server.
            Return username on success, None on failure.
        """
        if not username or not password:
            return None

        # old user
        user = get_userstore().getUser(username)
        if user:
            authentication_name = self.auth_store.get_authentication_method(user.authentication_key)
            auth_module = self._get_auth_module(authentication_name)
            if auth_module:
                auth_username = auth_module.authenticate(username, password)
                if auth_username:
                    User.update_last_login(auth_username)
                    return auth_username
            return None

        # new user
        for x in conf.authentication_order:
            auth_module = self._get_auth_module(x)
            if auth_module:
                auth_username = auth_module.authenticate(username, password)
                if auth_username:
                    User.update_last_login(auth_username)
                    return auth_username
        return None
Example #21
0
    def remove_user_from_group(self, user_name, group_name):
        """
        Removes user from group.
        Updates the published time of the project accordingly.

        :param str user_name: User name
        :param str group_name: Group name
        :raises InvalidPermissionState: User cannot be removed
        :raises DatabaseError: Query failure
        :raises ValueError: User not found
        """
        user = get_userstore().getUser(user_name)
        if not user:
            raise ValueError('User not found')

        # TODO: just check that there's TRAC_ADMIN left?
        # Checks that it is ok to remove user from group
        ug = self.get_all_user_groups()
        ug = [(user, group) for user, group in ug if not (user == user_name and group == group_name)]
        self.is_valid_group_members(user_groups=ug)

        group_name = group_name.encode('utf-8')
        group_id = self.get_group_id(group_name)
        self._cache.clear_user_groups(self.trac_environment_key)

        with admin_query() as cursor:
            cursor.callproc("remove_user_from_group", [user.id, group_id])

        self._update_published_time()
Example #22
0
    def list_users(self, req):
        """
        Handle user listing
        """
        req.perm.require('USER_AUTHOR')

        data = {}
        userstore = get_userstore()

        # State
        data['states'] = userstore.USER_STATUS_LABELS

        # Available backend organizations
        # TODO: Add support for listing users based on organization in user REST API
        orgman = self.env[OrganizationManager]
        data['organizations'] = [org for org in orgman.get_organizations() if org['type'] == 'backend']

        # Add jquery ui for autocomplete
        add_script(req, 'multiproject/js/jquery-ui.js')
        add_script(req, 'multiproject/js/transparency.js')
        add_script(req, 'multiproject/js/multiproject.js')
        add_script(req, 'multiproject/js/admin_user_list.js')
        add_stylesheet(req, 'multiproject/css/jquery-ui.css')

        return 'admin_user_list.html', data
Example #23
0
    def render_preference_panel(self, req, panel):
        """ Renders preference panel and handles image change on POST
        """

        if req.authname == 'anonymous':
            raise TracError("User is not authenticated", "No access")

        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        if req.method == 'POST':
            if 'removeicon' in req.args:
                user.icon = None
                userstore.updateUser(user)
            elif 'icon' in req.args:
                user.createIcon(req.args['icon'])

                if user.icon:
                    userstore.updateUser(user)

        data = {'user':user, 'base_path':req.base_path}
        if 'limitexceeded' in req.args:
            add_warning(req, 'Picture you tried to upload was too big. Try a smaller one.')

        return 'multiproject_user_prefs_image.html', data
Example #24
0
    def list_users(self, req):
        """
        Handle user listing
        """
        req.perm.require('USER_AUTHOR')

        data = {}
        userstore = get_userstore()

        # State
        data['states'] = userstore.USER_STATUS_LABELS

        # Available backend organizations
        # TODO: Add support for listing users based on organization in user REST API
        orgman = self.env[OrganizationManager]
        data['organizations'] = [org for org in orgman.get_organizations() if org['type'] == 'backend']

        # Add jquery ui for autocomplete
        add_script(req, 'multiproject/js/jquery-ui.js')
        add_script(req, 'multiproject/js/transparency.js')
        add_script(req, 'multiproject/js/multiproject.js')
        add_script(req, 'multiproject/js/admin_user_list.js')
        add_stylesheet(req, 'multiproject/css/jquery-ui.css')

        return 'admin_user_list.html', data
Example #25
0
def _chrome_format_author_replacement(self, req, author):
    """
    Audit Chrome.format_author method so that we get link to user profile

    Downside: This is a hack that interfere with the way trac renders usernames.
              Will have some unwanted behaviour.

              One such known unwanted behaviour is in the ticket view where owner and
              reporter links are changed
    """
    if not author:
        return ""
    unwanted_users = ['trac', 'tracadmin', 'anonymous', 'authenticated', 'somebody']
    not_ticket = req.path_info.rsplit('/', 2)[1] != 'ticket'
    contain_email = bool(re.search('<.+>', author))
    ok_user = author not in unwanted_users
    username = author
    if not contain_email:
        user = get_userstore().getUser(author)
        if user:
            author = user.getDisplayName()
    elif not Chrome(self.env).show_email_addresses:
        author = obfuscate_email_address(author)

    # Create a link to profile page or return author in plain
    if ok_user and not_ticket and not contain_email and conf.public_user_page_url:
        return tag.a(author, **{'href':conf.public_user_page_url + username, 'class':'author'})
    else:
        return author
Example #26
0
    def _list_message_groups(self, req):
        """
        Returns list of message groups: messages grouped by the sender
        """
        # Check permission from home env
        home_env = HomeProject().get_env()
        perm = PermissionCache(home_env, req.authname)
        query = req.args.get('q') or None # If empty, return latest
        limit = req.args.get('limit', 5)

        # Convert types
        try:
            limit = int(limit)
        except ValueError:
            return send_json(req, {'result': 'Invalid request'}, status=403)

        # Check permission
        if 'MESSAGE_VIEW' not in perm:
            return send_json(req, {'result': 'Permission denied'}, status=403)

        msgsrv = self.env[MessageService]
        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        # TODO: Permission checks?
        return send_json(req, msgsrv.get_messages_grouped_by(user.id, query=query, limit=limit))
 def get_preference_panels(self, req):
     """ Give name of the panel
     """
     user = get_userstore().getUser(req.authname)
     has_external_avatar = Authentication().has_external_profile(user)
     if req.authname != 'anonymous' and not has_external_avatar:
         yield ('image', 'Face image')
Example #28
0
    def get_projects_with_rights(self, username, action):
        """
        :returns: a list of projects where user have right for "action".

        .. note::

           Permissions coming via LDAP groups are not included in the results

        """
        user = get_userstore().getUser(username)

        # Get subjects
        subjects = set([username])
        subjects.update(get_special_users(username))

        # Surround string elements with ' and join them with comma
        actions_str = ','.join("'%s'" % safe_string(p) for p in [action, 'TRAC_ADMIN'])
        subjects_str = ','.join(["'{0}'".format(safe_string(subject)) for subject in subjects])
        organizations_str = ','.join(["{0}".format(safe_int(org_key)) for org_key in user.organization_keys])

        query = ("SELECT DISTINCT projects.* FROM projects "
                 "INNER JOIN `group` ON group.trac_environment_key = projects.trac_environment_key "
                 "INNER JOIN group_permission ON group_permission.group_key = group.group_id "
                 "INNER JOIN action ON group_permission.permission_key = action.action_id "
                 "LEFT JOIN user_group ON user_group.group_key = group.group_id "
                 "LEFT JOIN user ON user.user_id = user_group.user_key "
                 "LEFT JOIN organization_group ON organization_group.group_key = group.group_id "
                 "WHERE (user.username IN(%s) "
                 "OR organization_group.organization_key IN(%s)) "
                 "AND action.action_string IN(%s) "
                 "ORDER BY projects.project_name" % (subjects_str, organizations_str, actions_str))

        return self.queryProjectObjects(query)
Example #29
0
    def get_participated_public_projects(self, username):
        """ Get public projects username has participated in
        """
        store = get_userstore()
        user = store.getUser(username)
        if not user:
            return []

        anon = store.getUser('anonymous')

        order = " ORDER BY projects.project_name"

        # We need projects where _both_ anonymous and the specified user exist
        query = """
        SELECT projects.environment_name AS name, projects.description AS description, projects.created AS date,
          '%(user_name)s' AS author, projects.project_name, projects.icon_name
        FROM projects
        INNER JOIN `group` ON group.trac_environment_key = projects.trac_environment_key
        INNER JOIN user_group ON user_group.group_key = group.group_id
        INNER JOIN `user` ON user_group.user_key = user.user_id
        WHERE user_group.user_key = %(user_id)d AND EXISTS
        (SELECT * FROM projects P
        INNER JOIN `group` ON `group`.trac_environment_key = P.trac_environment_key
        INNER JOIN user_group ON user_group.group_key = group.group_id
        WHERE user_group.user_key = %(anon_id)d AND projects.project_id = P.project_id)
        """ % {"user_name": safe_string(user.getDisplayName().encode('utf-8')),
               "user_id": safe_int(user.id), "anon_id": safe_int(anon.id)}
        query += order
        return self.__queryProjectsWithDescr(query)
Example #30
0
    def public_project_count(self):
        """ Number of public projects
        """

        # Chances are that we get these from the cache
        anon = get_userstore().getUser('anonymous')
        auth = None #users.getUser('authenticated')

        users_in = []
        if anon:
            users_in.append(str(safe_int(anon.id)))
        if auth:
            users_in.append(str(safe_int(auth.id)))
        users_in_str = ','.join(users_in)

        query = ("SELECT count(DISTINCT project_id) FROM projects "
                 "INNER JOIN `group` ON `group`.trac_environment_key = projects.trac_environment_key "
                 "INNER JOIN user_group ON user_group.group_key = `group`.group_id "
                 "WHERE user_group.user_key IN(%s)" % users_in_str)

        count = 0
        with admin_query() as cursor:
            cursor.execute(query)
            row = cursor.fetchone()
            count = row[0]

        return count
    def render_preference_panel(self, req, panel):
        """ Renders preference panel and handles image change on POST
        """

        if req.authname == 'anonymous':
            raise TracError("User is not authenticated", "No access")

        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        if req.method == 'POST':
            if 'removeicon' in req.args:
                user.icon = None
                userstore.updateUser(user)
            elif 'icon' in req.args:
                user.createIcon(req.args['icon'])

                if user.icon:
                    userstore.updateUser(user)

        data = {'user': user, 'base_path': req.base_path}
        if 'limitexceeded' in req.args:
            add_warning(
                req,
                'Picture you tried to upload was too big. Try a smaller one.')

        return 'multiproject_user_prefs_image.html', data
    def _do_save(self, req, user):
        """ Update user information into database
        """
        userstore = get_userstore()

        if not req.args.get('mail'):
            add_warning(req, _('User should have an e-mail address'))
            return user

        user.mail = req.args.get('mail')

        if not req.args.get('lastName'):
            add_warning(req, _('Last name required'))
            return user

        # NOTE: Values are escaped in userstore update
        user.lastName = req.args.get('lastName')
        user.givenName = req.args.get('givenName')
        user.mobile = req.args.get('mobile')

        if userstore.updateUser(user):
            user = userstore.getUser(user.username)
            add_notice(req, _('Updated user settings'))

            if req.args.get(
                    'approve') == 'on' and user.status == user.STATUS_INACTIVE:
                user.activate()
                add_notice(req, _("Your account is now activated."))

            return user

        add_warning(req, _('Failed to update user'))
        return user
    def get_anonymous_user_id(self):
        anon = get_userstore().getUser('anonymous')
        if anon:
            anon_id = safe_int(anon.id)
        else:
            anon_id = None

        return anon_id
Example #34
0
    def get_anonymous_user_id(self):
        anon = get_userstore().getUser('anonymous')
        if anon:
            anon_id = safe_int(anon.id)
        else:
            anon_id = None

        return anon_id
Example #35
0
    def _list_expired(self, when=None):
        # Parse optional date argument
        when = when if when is None else datetime.strptime(when, '%Y-%m-%d')

        userstore = get_userstore()
        users = [(user.username, user.expires) for user in userstore.get_expired_users(when=when)]

        print_table(users, ('User', 'Expires'))
Example #36
0
 def _init_session(self, req, remote_user):
     # Some modules uses name and email data from session, so lets put them there
     userstore = get_userstore()
     user = userstore.getUser(remote_user)
     req.session['name'] = user.getDisplayName()
     req.session['email'] = user.mail
     req.session['displayname'] = user.getDisplayName()
     req.session.save()
    def notify_now(self, notification_frequency):
        """
        Send notification email to project watchers.

        :param str notification_frequency: The notification frequency, used to fetch
            users which have something on that watchlist.
        """
        store = CQDEWatchlistStore()
        watches = store.get_by_notification(notification_frequency)

        notifylist = {}
        for w in watches:
            if notifylist.get(w.project_id) is None:
                notifylist[w.project_id] = []
            notifylist[w.project_id].append(w.user_id)

        userstore = get_userstore()

        counter = 0
        for project_id in notifylist.keys():
            project = Project.get(id=project_id)

            # Get all events for this project
            events = self._get_project_events(project, notification_frequency)

            # Send one email per user, because everyone may have a different
            # set of permissions (i.e. which events he/she has permission to see)
            for user_id in notifylist[project_id]:
                user = userstore.getUserWhereId(user_id)
                if user:
                    # filter eventlist by user's permissions
                    filtered_events = WatchlistEvents(self.env).filter_events(
                        events, user, project)
                    if filtered_events:
                        addresses = [user.mail]
                        message = self._format_message(user, project,
                                                       filtered_events)
                        title = "Project updated: %s" % project.env_name
                        mail = EmailNotifier(self.env,
                                             subject=title,
                                             data={'body': message})
                        mail.notify_emails(addresses)
                        self.env.log.debug('Sent email notification to: %s' %
                                           user)
                        counter += 1
                    else:
                        if notification_frequency != 'immediate':
                            self.env.log.debug(
                                'No events to sent to %s about %s' %
                                (user, project))
                else:
                    self.env.log.warning(
                        'User %d in notification list was not found in userstore'
                        % user_id)

        # Log the results
        self.env.log.info('Sent %s watchlist notifications (%s)' %
                          (counter, notification_frequency))
Example #38
0
    def creator(self):
        """
        Returns the creator user if set
        :return: User
        """
        if not self.creator_id:
            raise Exception('MessageGroup has no creator')

        return get_userstore().getUserWhereId(self.creator_id)
Example #39
0
    def update_user_data(self, req):
        """ Updates all user data into session
        """
        user = get_userstore().getUser(req.authname)

        req.session['email'] = user.mail
        req.session['name'] = user.getDisplayName()
        req.session['displayname'] = user.getDisplayName()
        req.session.save()
Example #40
0
    def get_user_project_groups(self, audit_username):
        user = get_userstore().getUser(audit_username)
        user_groups = self._store.get_all_user_groups()

        groups = []
        for username, group in user_groups:
            if username == user.username:
                groups.append(group)

        return groups
Example #41
0
    def _apply_changes(self, req, project):
        """
        Saves changes into database and project configuration file
        """
        try:
            # Save information into database
            project.project_name = req.args.get('name')
            project.description = req.args.get('descr')

            # Update author if needed
            author_id = req.args.get('author_id')
            if author_id and project.author_id != int(author_id):
                userstore = get_userstore()
                author = userstore.getUserWhereId(author_id)
                project.author = author

                # Check if author has admin permission to project: put in project if not
                authorperm = PermissionCache(self.env, author.username)
                if 'TRAC_ADMIN' not in authorperm:
                    admin_rights = False
                    groupstore = CQDEUserGroupStore(
                        project.trac_environment_key)
                    # Iterate existing project groups and put user into group with TRAC_ADMIN rights
                    for gname, pname in groupstore.get_all_group_permissions():
                        if pname == 'TRAC_ADMIN':
                            groupstore.add_user_to_group(
                                author.username, gname)
                            admin_rights = True
                            add_notice(
                                req,
                                _('Added TRAC_ADMIN permissions to user: {0}'.
                                  format(author.username)))

                    if not admin_rights:
                        permlink = tag.a(
                            'You way want to modify permissions',
                            href=req.href('admin/general/permissions'))
                        add_warning(
                            req,
                            tag(
                                _('User {0} does not have administrative rights to project. '
                                  .format(author.username)), permlink))

            # Save changes to database
            project.save()

            # Save information into config
            for option in ('name', 'descr'):
                self.config.set('project', option, req.args.get(option))
            self.config.save()

        except Exception, e:
            self.log.exception('Failed to save project changes')
            add_warning(req, _('Failed to save changes: {0}'.format(e)))
            return req.redirect(req.href('admin/general/basics'))
Example #42
0
    def _mark_read(self, req):
        """
        Marks message / messages within a group read

        :param Request req:
            Trac requst with following arguments:

            - message_id: Message id
            - group_id: Message group id

            .. NOTE::

               Either ``message_id`` or ``group_id`` needs to be provided

        :return: JSON response with result: 'OK' or error
        """
        # NOTE: Depends on NotificationSystem. Moving method in NotificationRestAPI does not make sense either
        # because Notification system is generic and does not know about the MessageGroups

        if not self.env.is_component_enabled('multiproject.common.notifications.push.NotificationSystem'):
            return send_json(req, {'result': 'NotificationSystem is not enabled/available'}, status=500)

        group_id = req.args.get('group_id', None)
        message_id = req.args.get('message_id', None)

        # Load NotificationSystem
        from multiproject.common.notifications.push import NotificationSystem
        ns = self.env[NotificationSystem]

        # Load user (anon check already done at this point)
        user = get_userstore().getUser(req.authname)
        chname = ns.generate_channel_name(user_id=user.id)

        # Load specified message group
        if message_id:
            msg = Message.get(message_id)
            if not msg:
                return send_json(req, {'result': 'Message was not found'}, status=404)
            ns.reset_notification(chname, {'id': msg.id, 'type': 'message'})

        # Reset all messages within a group
        elif group_id:
            mg = MessageGroup.get(group_id)
            if not mg:
                return send_json(req, {'result': 'Message group or user was not found'}, status=404)

            # Generate notification keys based on group messages
            notification_keys = ['message-%d' % msg.id for msg in mg.get_messages()]
            ns.reset_notifications(chname, keys=notification_keys)

        # Missing required arguments
        else:
            return send_json(req, {'result': 'Invalid request'}, status=400)

        return send_json(req, {'result': 'OK'})
Example #43
0
    def remove_superuser(self, username):
        """ Add user to superusers list
        """
        userstore = get_userstore()
        if not userstore.userExists(username):
            return False

        if _call_proc_with_success("remove_superuser", [username]):
            self._cache.clear_superusers()
            return True
        return False
Example #44
0
    def render_preference_panel(self, req, panel):
        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        if req.authname == 'anonymous' or not userstore.is_local(user):
            raise TracError("User is not authenticated or preferences are maintained separate service", "No preferences")

        if req.method == 'POST':
            self.changePassword(req)

        return 'multiproject_user_prefs_password.html', {}
Example #45
0
    def _get_team_info(self, project):
        """
        Reads team members and sorts them so that default groups
        are first and other groups are last (in alphabetical order)

        :param Project project: Project to retrieve team info from
        :returns: tuple of data: teams, members
        """
        ug = CQDEUserGroupStore(project.trac_environment_key)
        team = sorted(ug.get_all_user_groups(), key=lambda tmp: tmp[1])

        # TODO: Implement better

        default_group_names = [tuple[0] for tuple in conf.default_groups]
        default_group_names += [
            conf.public_auth_group[0], conf.public_anon_group[0]
        ]
        first = {}
        last = {}
        all_members = {}

        # Create group => member hash
        userstore = get_userstore()
        for member, group in team:
            all_members[member] = 1
            account = userstore.getUser(username=member)

            if group in default_group_names:
                if group not in first:
                    first[group] = []
                first[group].append(account)
            else:
                if group not in last:
                    last[group] = []
                last[group].append(account)

        # Create group, memberlist tuples from items and keep them sorted
        # First read the default groups in to list of tuples in the order they are defined in conf
        items = []
        for group in default_group_names:
            if first.has_key(group):
                items += [(group, first[group])]

        # Then append other groups in alphabetical order
        items += sorted(last.items(), key=lambda tmp: tmp[0])

        # Then join all the members as a one markup string with member links
        teams = []
        for group, members in items:
            teams.append((group, members))

        # Team members in (group, member_uri) type, and all member names
        return teams, all_members.keys()
Example #46
0
    def get_team(self):
        """ Returns a list of those users that have rights to project
        """
        query = ("SELECT DISTINCT user.* FROM user "
                 "INNER JOIN user_group ON user.user_id = user_group.user_key "
                 "INNER JOIN `group` ON user_group.group_key = group.group_id "
                 "WHERE group.trac_environment_key = %d "
                 "AND user.username NOT IN('anonymous', 'authenticated')" %
                 safe_int(self.trac_environment_key))

        userstore = get_userstore()
        return userstore.query_users(query)
Example #47
0
    def render_admin_panel(self, req, cat, page, path_info):
        """ Overrides BasicsAdminPanel rendering function.

            Handle project info update (update global db) and then
            delegate handling back to BasicsAdminPanel
        """
        req.perm.require('TRAC_ADMIN')
        userstore = get_userstore()
        user = userstore.getUser(req.authname)
        project = Project.get(self.env)

        # Update database if form posted
        if req.method == 'POST':
            # Remove icon if requested
            if 'reset' in req.args:
                # NOTE: Icon is removed from filesystem already at this point
                self._unset_icon(req, project)
                project.icon_name = None

            # Update icon if set
            if not isinstance(req.args.get('icon', ''), basestring):
                icon_name = self._set_icon(req, project)
                if icon_name:
                    # If image is changed
                    if icon_name != project.icon_name:
                        self._unset_icon(req, project)
                    project.icon_name = icon_name
                else:
                    add_warning(req, 'Failed to set the project icon')

            # Save changes in database
            if 'apply' in req.args:
                self._apply_changes(req, project)

            # Reload page
            return req.redirect(req.href(req.path_info))

        data = {
            'user': user,
            'icon_size': self.icon_size,
            'mproject': project,
            'allow_public_projects': conf.allow_public_projects
        }

        # Add javascript libraries for datepicker and autocomplete
        add_script(req, 'multiproject/js/jquery-ui.js')
        add_stylesheet(req, 'multiproject/css/jquery-ui.css')
        add_script(req, 'multiproject/js/multiproject.js')
        add_script(req, 'multiproject/js/admin_basics.js')

        Chrome(self.env).add_textarea_grips(req)
        return 'admin_basics_replacement.html', data
Example #48
0
    def author(self):
        """
        Property for getting project author

        :returns: User instance of the project author
        """
        if self._author:
            return self._author

        userstore = get_userstore()
        self._author = userstore.getUserWhereId(self.author_id)

        return self._author
    def render_preference_panel(self, req, panel):
        userstore = get_userstore()
        user = userstore.getUser(req.authname)

        if req.authname == 'anonymous' or not userstore.is_local(user):
            raise TracError(
                "User is not authenticated or preferences are maintained separate service",
                "No preferences")

        if req.method == 'POST':
            self.changePassword(req)

        return 'multiproject_user_prefs_password.html', {}
Example #50
0
    def createProject(self, req, projectid, projectname, description, project_visibility, serviceslist):
        """ Request to create a new project
        """
        services = {}

        if str(projectid).strip() == '':
            e = exceptions.Exception
            raise e("Incorrect project identification name")

        if str(projectname).strip() == '':
            e = exceptions.Exception
            raise e("Incorrect project name")

        users = get_userstore()
        author = users.getUser(req.authname)

        if not author.can_create_project():
            raise Exception("You are not allowed to create projects")
        
        public = False
        published = None
        if project_visibility == "on" or project_visibility == "true":
            public = True
            published = datetime.now()

        # Create project class
        project = Project(id=None,
                          env_name=unicode(projectid),
                          project_name=projectname,
                          description=description,
                          author_id=author.id,
                          created=None,
                          public=public,
                          published=published)

        if project_visibility == "on" or project_visibility == "true":
            services['project_visibility'] = 'on'
        else:
            services['project_visibility'] = 'off'

        projects = Projects()
        projects.getServices(services, serviceslist)

        # Create project
        try:
            projects.create_project(project, services)
            return self.get_scm_repository_url(project.env_name)
        except ProjectValidationException as exc:
            raise Exception(exc.value)
        except:
            raise Exception("Creating project failed. Try again later.")
Example #51
0
 def modify_changeset_cntxtnav(self, req, data):
     if not data:
         self.log.error(
             'modify_changeset_cntxtnav problem ocurres with path_info: %s args: %s'
             % (req.path_info, req.args))
         return
     if data['changeset']:
         data['owner'] = get_userstore().getUser(data['changeset'].author)
     ctxtnavitems = req.chrome.pop('ctxtnav', [])
     add_ctxtnav(req, _('All sources'), href=req.href.browser())
     add_ctxtnav(req, _('Last change'))
     add_ctxtnav(req, _('Revision log'), href=req.href.log())
     add_ctxtnav(req, _('Diff changesets'), href=req.href.diff())
     self.filter_navitems(ctxtnavitems, req, data)
Example #52
0
    def _user_name_or_mail_exists(self, req):
        """
           Returns JSON representation for requested username or mail
        """

        query = req.args.get('q', '')[:100]

        if not query:
            self.log.exception("query string not given. %s" % query)
            return req.send('', status=404)

        userstore = get_userstore()
        recordExists = userstore.userNameOrMailExists(query)
        
        return send_json(req, recordExists)
Example #53
0
    def validate_user(self, req, user):
        if get_userstore().userExists(user.username):
            return 'User name already reserved'

        if not user.username:
            return 'User should have a username'

        if user.username.find(':') != -1 or user.username.find('%') != -1:
            return 'User name cannot contain characters: : %'

        if not user.mail:
            return 'User should have an e-mail address'

        if not user.lastName:
            return 'Last name required'
    def get_download_data(self):
        platforms = {}
        downloads = []

        def download_from_sql_row(row):
            return {
                'id': row[0],
                'file': row[1],
                'description': row[2],
                'time': row[3],  # in timestamp, not in utimestamp
                'count': row[4],
                'author': row[5],
                'platform': row[6],  # Will be string instead
                'featured': row[7]
            }

        try:
            db = self.env.get_read_db()
            cursor = db.cursor()
            cursor.execute("SELECT id, name FROM platform")
            for row in cursor:
                platforms[row[0]] = row[1]
            cursor.execute(
                "SELECT id, file, description, time, count, author, platform, featured FROM download"
            )
            for row in cursor:
                downloads.append(download_from_sql_row(row))
        except Exception as e:
            env_name = conf.resolveProjectName(self.env)
            # this is the only way, since there are no common exceptions
            if e.__class__.__name__ == 'ProgrammingError':
                printout("{0}: Get download data failed: {1}".format(
                    env_name, e))
                return None
            else:
                raise
        userstore = get_userstore()
        for download in downloads:
            user = userstore.getUser(download['author'])
            if user:
                download['author_id'] = user.id
            else:
                download['author_id'] = None
            if not download['platform']:
                download['platform'] = ''
            else:
                download['platform'] = platforms[download['platform']]
        return downloads
Example #55
0
    def get_user_permissions(self, subject):
        """
        Returns the permissions of the specific subject (user or group)

        .. NOTE::

            Argument ``subject`` can be group or user, even though method name
            would indicate only user being correct. This is how Trac
            implements groups (at least in 0.12)

        :returns: List of permission names
        """
        user = get_userstore().getUser(subject)

        if user is not None:
            # construct list of groups where user belongs to
            groups = []
            for username, group in self._store.get_all_user_groups():
                if username == user.username:
                    groups.append(group)

            # add organization groups
            org_store = CQDEOrganizationStore.instance()
            for organization, group in self._store.get_all_organization_groups():
                org_id = org_store.get_organization_id(organization)
                if org_id in user.organization_keys:
                    groups.append(group)

            # construct list of permissions based on group list
            permissions = []
            for group, perm in self._store.get_all_group_permissions():
                if group in groups:
                    permissions.append(perm)

            return permissions
        else:
            # no such user, asked with group name
            group_store = CQDEUserGroupStore(self.trac_environment_key)
            permissions = []
            for name, permission in group_store.get_all_group_permissions():
                if permission is None:
                    # TODO: this should NOT happen!
                    conf.log.warning('Group %s has permission None in trac_environment_key %s!' %
                                     (subject, self.trac_environment_key))
                    continue
                if name == subject:
                    permissions.append(permission)
            return permissions