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))
 def notify_now(self, env):
     home_project = HomeProject()
     listofprojects = ""
     projects = self.get_notified_projects()
     for name in projects.keys():
         if projects[name].notifynow:
             listofprojects += name + self.tabspace(len(name)) + str(projects[name].totalsize) + "\n"
     if len(listofprojects) > 0:
         # TODO: Move into template
         message = "These projects exceeded system storage limit:\n(storage limit = " +\
                   str(long(conf.storage_locking_limit)) + " bytes)\n\n"
         message += listofprojects
         mail = EmailNotifier(env, "Project(s) exceeded storage limits", message)
         mail.notify_system_admins(home_project)
    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 #4
0
    def _send_notification(self, user):
        """
        Send account information to new user

        :param User user:
        :raises: TracError if email sending fails
        """
        data = {
            'system':conf.domain_name,
            'username':user.username,
            'password':user.password,
            'expires':user.expires
        }
        enotify = EmailNotifier(self.env, "New user account created", data)
        enotify.template_name = "local_account_created.txt"
        enotify.notify(user.mail)
Example #5
0
 def notify_now(self, env):
     home_project = HomeProject()
     listofprojects = ""
     projects = self.get_notified_projects()
     for name in projects.keys():
         if projects[name].notifynow:
             listofprojects += name + self.tabspace(len(name)) + str(
                 projects[name].totalsize) + "\n"
     if len(listofprojects) > 0:
         # TODO: Move into template
         message = "These projects exceeded system storage limit:\n(storage limit = " +\
                   str(long(conf.storage_locking_limit)) + " bytes)\n\n"
         message += listofprojects
         mail = EmailNotifier(env, "Project(s) exceeded storage limits",
                              message)
         mail.notify_system_admins(home_project)
Example #6
0
    def _send_notification(self, user, server_name):
        """
        Send account information to new user

        :param User user:
        :raises: TracError if email sending fails
        """

        data = {
            'system': server_name,
            'username': user.username,
            'password': user.password,
            'expires': user.expires
        }
        enotify = EmailNotifier(self.env, "New user account created", data)
        enotify.template_name = "local_account_created.html"
        enotify.notify(user.mail)
Example #7
0
    def process_request(self, req):
        """
        Takes the provided arguments and posts an email to author

        - username: User account whose password needs to be changed
        - token: Validation token generated by system

        """
        back_url = req.href()
        username = req.args.get('username', '')
        token = req.args.get('token', '')

        # Check if required parameters are set
        if not username or not token:
            add_warning(req, _('Invalid request'))
            return req.redirect(back_url)

        # Check if user really exists
        userstore = get_userstore()
        user = userstore.getUser(username)
        if not user:
            add_warning(req, _('Invalid request'))
            return req.redirect(back_url)

        # Check token
        if token != get_token(self.env, user):
            add_warning(req, _('Invalid request'))
            return req.redirect(back_url)

        # Construct and send email
        manage_url = self.env.abs_home_href(
            'admin/users/manage',
            username=user.username
        )
        data = {
            'user':user,
            'domain_name':self.env.config.get('multiproject', 'domain_name'),
            'manage_url':manage_url
        }

        # Get author email address
        author = userstore.get_user_author(user)
        if not author or not author.mail:
            add_warning(req, _('Author email not found - please contact service support instead'))
            return req.redirect(back_url)

        try:
            # Import module here so that multiproject.common.users can be imported easily/without circular dependencies
            from multiproject.common.notifications.email import EmailNotifier

            # Open home environment
            home_env = get_home(self.env)
            enotify = EmailNotifier(home_env, 'Password reset requested', data)
            enotify.template_name = 'multiproject_reset_password.txt'
            enotify.notify(author.mail)
            add_notice(req, _('Password reset requested - you will be informed about the new password once changed'))
        # Email sending failed
        except TracError:
            add_warning(req, _('Email sending failed - please try again later'))

        # Return back to homepage
        return req.redirect(back_url)
Example #8
0
    def edit_user(self, req):
        """
        Handle user edit: view & save
        """
        changes = {}

        username = req.args.get('username')
        if not username:
            add_warning(req, _('Invalid username'))
            return self.list_users(req)

        # Load user being edited
        userstore = get_userstore()
        user = userstore.getUser(username)
        if not user:
            add_warning(req, _('Invalid username (or connection error)'))
            return self.list_users(req)

        # Load user who's doing the edit
        changed_by = userstore.getUser(req.authname)
        papi = Projects()

        # Check permissions and redirect to user listing (handy after editing the user)
        req.perm.require('USER_AUTHOR', Resource('user', id=user.id))

        data = req.args
        data['user'] = user
        data['author'] = userstore.getUserWhereId(user.author_id) if user.author_id else None
        data['base_path'] = req.base_path
        data['dateformats'] = DATEFORMATS
        data['is_local'] = userstore.is_local(user)
        data['now'] = datetime.utcnow()
        data['expired'] = user.expires and ((user.expires - datetime.utcnow()).days < 0)
        data['states'] = userstore.USER_STATUS_LABELS
        data['projects'] = papi.get_authored_projects(user)

        # 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_user_edit.js')

        # If get request show edit
        if req.method.upper() == 'GET':
            return 'admin_user_edit.html', data

        # Close pressed: get back to user listing
        if req.args.get('close'):
            return req.redirect(req.href('admin/users/manage'))

        # Handle save
        if 'limitexceeded' in req.args:
            add_warning(req, _('Picture you tried to upload was too big. Try a smaller one'))

        # Update author if changed
        author_id = req.args.get('author_id', None)

        # If id field is empty but name is not: manual input
        if not author_id and req.args.get('author_text'):
            add_warning(req, _('Author cannot be found'))
            return 'admin_user_edit.html', data

        # Check set reset the author
        if author_id:
            author = userstore.getUserWhereId(int(author_id))
            if not author:
                add_warning(req, _('Author cannot be found'))
                return 'admin_user_edit.html', data

            # Check if author is valid: has permission to author?
            perm = PermissionCache(self.env, author.username)
            if 'USER_AUTHOR' not in perm:
                add_warning(req, _('User %s cannot work as an author (does not have USER_AUTHOR permissions)' % author))
                return self.back(req)

            user.author_id = author.id
            changes['author'] = author
        else:
            user.author_id = None

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

        old_mail = user.mail
        user.mail = req.args.get('email')
        if not user.mail:
            add_warning(req, _('Email address required'))
            return self.back(req)

        if old_mail != user.mail:
            changes['email'] = user.mail
            org_store = CQDEOrganizationStore.instance()
            # TODO: is this correct?
            # When changing email, reset organizations to which the user belongs in
            user.organization_keys = org_store.get_organization_keys(user) or None

        # Update password if changed
        password = req.args.get('password')
        if password:
            if not userstore.is_local(user):
                add_warning(req, _("Can't change password for user that uses external authentication method"))
                return self.back(req)

            if len(password) < 7:
                add_warning(req, _("Password must be at least 7 characters long - please provide longer password"))
                return self.back(req)

            if password != req.args.get('confirmpw'):
                add_warning(req, _("Password do not match - please check"))
                return self.back(req)

        user.givenName = req.args.get('first')
        user.mobile = req.args.get('mobile')

        # Set or reset account expiration date
        expiration_str = req.args.get('expires', '')
        if expiration_str:
            try:
                # Parse date and set expiration time in the end of the day
                expires = datetime.strptime(expiration_str, DATEFORMATS['py'])
                expires += timedelta(hours=23, minutes=59, seconds=59)

                # If changed
                if expires != user.expires:
                    user.expires = expires
                    changes['expiration_date'] = user.expires.strftime(DATEFORMATS['py'])

            except Exception:
                self.log.exception('Date formatting failed')
                add_warning(req, _('Non-recognized expiration format'))
                pass

        # Remove expiration date
        elif user.expires:
            changes['expiration_date'] = 'Never expires'
            user.expires = None

        # Update status if set
        status = int(req.args.get('status', 0))
        if status and status in userstore.USER_STATUS_LABELS.keys() and user.status != status:
            changes['status'] = userstore.USER_STATUS_LABELS[status]
            user.status = status

        if req.args.get('removeicon'):
            user.icon = None
        else:
            icon = req.args.get('icon')
            if not isinstance(icon, unicode) and icon.filename:
                user.createIcon(req.args.get('icon'))

        self.log.info('Saving changes to user: %s' % user)
        ok = userstore.updateUser(user)
        if ok and password:
            changes['password'] = password
            ok = userstore.updatePassword(user, password)

        if not ok:
            add_warning(req, _("Could not save changes"))

        add_notice(req, _("User %s updated" % username))

        # Notify user about changes via email?
        if req.args.get('notify'):
            data = {
                'user':user,
                'changed_by':changed_by,
                'changes':changes
            }

            try:
                enotify = EmailNotifier(self.env, "Account updated", data)
                enotify.template_name = 'account_edited.txt'
                enotify.notify(user.mail)
                add_notice(req, _("Notified user about the changes"))
            except TracError:
                add_warning(req, _("Failed to send email notification - user changed anyway"))

        # Check if user has still (after modification) permission to modify user
        # NOTE: req.perm cannot be used here because it is not updated yet
        resource = Resource('user', id=user.id)
        perm = PermissionCache(self.env, username=req.authname)
        if perm.has_permission('USER_AUTHOR', resource):
            return self.back(req)

        add_notice(req, _('You have no longer permission to modify the account: %s' % user.username))
        return req.redirect(req.href('admin/users/manage'))
def main():
    if '-h' in sys.argv or '--help' in sys.argv:
        print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
        sys.exit()
    from_batch = 0
    if '--batch' in sys.argv:
        from_batch_index = sys.argv.index('--batch')+1
        if len(sys.argv) > from_batch_index:
            from_batch = int(sys.argv[int(from_batch_index)])
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
            print "       (--batch used incorrectly)"
            sys.exit()
    from_sleep = 5
    if '--sleep' in sys.argv:
        from_sleep_index = sys.argv.index('--sleep')+1
        if len(sys.argv) > from_sleep_index:
            from_sleep = int(sys.argv[int(from_sleep_index)])
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
            print "       (--sleep used incorrectly)"
            sys.exit()
    total_batch_count = -1
    if '--limit' in sys.argv:
        from_limit_index = sys.argv.index('--limit')+1
        if len(sys.argv) > from_limit_index:
            total_batch_count = int(sys.argv[int(from_limit_index)])
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
            print "       (--limit used incorrectly)"
            sys.exit()

    env_name = 'HelpAndSupport'
    if '--env' in sys.argv:
        env_index = sys.argv.index('--env')+1
        if len(sys.argv) > env_index:
            env_name = sys.argv[int(env_index)]
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [-n] [--env ENV] "
            print "       (--env used incorrectly)"
            sys.exit()

    debug_only = False
    if '-n' in sys.argv:
        debug_only = True

    header = ''
    message = ''
    with open('message.txt') as fd:
        message = fd.read()
    with open('subject.txt') as fd:
        lines = fd.read().splitlines()
        for line in lines:
            if line:
                header = line

    mailNotifier = EmailNotifier(Environment(conf.getEnvironmentSysPath(env_name)),
            header, message)

    print "header: '%s'" % header
    print "message:\n---\n'%s'\n---\n" % message
    print "debug?:%s"%debug_only

    with open('project_admins.txt') as fd:
        users = fd.read().splitlines()

        index = 0
        counter = 0
        sent_batch_count = 0
        for chunk in chunks(users, 5):
            counter += 1
            if from_batch <= counter and (total_batch_count == -1 or total_batch_count > sent_batch_count):
                print "sending batch %s, from %s to %s, emails: %s" % (counter, index+1, index+len(chunk), chunk)
                if not debug_only:
                    mailNotifier.notify(chunk)
                time.sleep(from_sleep)
                sent_batch_count += 1
            index += 5
Example #10
0
def main():
    if '-h' in sys.argv or '--help' in sys.argv:
        print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
        sys.exit()
    from_batch = 0
    if '--batch' in sys.argv:
        from_batch_index = sys.argv.index('--batch') + 1
        if len(sys.argv) > from_batch_index:
            from_batch = int(sys.argv[int(from_batch_index)])
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
            print "       (--batch used incorrectly)"
            sys.exit()
    from_sleep = 5
    if '--sleep' in sys.argv:
        from_sleep_index = sys.argv.index('--sleep') + 1
        if len(sys.argv) > from_sleep_index:
            from_sleep = int(sys.argv[int(from_sleep_index)])
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
            print "       (--sleep used incorrectly)"
            sys.exit()
    total_batch_count = -1
    if '--limit' in sys.argv:
        from_limit_index = sys.argv.index('--limit') + 1
        if len(sys.argv) > from_limit_index:
            total_batch_count = int(sys.argv[int(from_limit_index)])
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [--sleep N] [-n] [--env ENV] "
            print "       (--limit used incorrectly)"
            sys.exit()

    env_name = 'HelpAndSupport'
    if '--env' in sys.argv:
        env_index = sys.argv.index('--env') + 1
        if len(sys.argv) > env_index:
            env_name = sys.argv[int(env_index)]
        else:
            print "Usage: python send_mail_to_project_admins.py [--batch N] [--limit N] [-n] [--env ENV] "
            print "       (--env used incorrectly)"
            sys.exit()

    debug_only = False
    if '-n' in sys.argv:
        debug_only = True

    header = ''
    message = ''
    with open('message.txt') as fd:
        message = fd.read()
    with open('subject.txt') as fd:
        lines = fd.read().splitlines()
        for line in lines:
            if line:
                header = line

    mailNotifier = EmailNotifier(
        Environment(conf.getEnvironmentSysPath(env_name)), header, message)

    print "header: '%s'" % header
    print "message:\n---\n'%s'\n---\n" % message
    print "debug?:%s" % debug_only

    with open('project_admins.txt') as fd:
        users = fd.read().splitlines()

        index = 0
        counter = 0
        sent_batch_count = 0
        for chunk in chunks(users, 5):
            counter += 1
            if from_batch <= counter and (
                    total_batch_count == -1
                    or total_batch_count > sent_batch_count):
                print "sending batch %s, from %s to %s, emails: %s" % (
                    counter, index + 1, index + len(chunk), chunk)
                if not debug_only:
                    mailNotifier.notify(chunk)
                time.sleep(from_sleep)
                sent_batch_count += 1
            index += 5
Example #11
0
    def edit_user(self, req):
        """
        Handle user edit: view & save
        """
        changes = {}

        username = req.args.get('username')
        if not username:
            add_warning(req, _('Invalid username'))
            return self.list_users(req)

        # Load user being edited
        userstore = get_userstore()
        user = userstore.getUser(username)
        if not user:
            add_warning(req, _('Invalid username (or connection error)'))
            return self.list_users(req)

        # Load user who's doing the edit
        changed_by = userstore.getUser(req.authname)
        papi = Projects()

        # Check permissions and redirect to user listing (handy after editing the user)
        #req.perm.require('USER_AUTHOR', Resource('user', id=user.id))
        if self.check_author_and_deputies(changed_by.id,
            user.author_id, userstore.get_deputies(user.id), req, user.id) == False:
            add_warning(req, _("You don't have rights to edit user"))
            req.redirect(req.href("admin"))

        data = req.args
        data['user'] = user
        data['author'] = userstore.getUserWhereId(user.author_id) if user.author_id else None
        data['deputies'] = userstore.get_deputies(user.id)
        data['base_path'] = req.base_path
        data['dateformats'] = DATEFORMATS
        data['is_local'] = userstore.is_local(user)
        data['now'] = datetime.utcnow()
        data['expired'] = user.expires and ((user.expires - datetime.utcnow()).days < 0)
        data['states'] = userstore.USER_STATUS_LABELS
        data['projects'] = papi.get_authored_projects(user)

        # 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_user_edit.js')

        # If get request show edit
        if req.method.upper() == 'GET' and req.args.get('remove_deputy'):
            deputy = userstore.getUser(req.args.get('remove_deputy').strip())
            remove_res = userstore.remove_deputy(user.id, deputy.id)
            return req.send(remove_res, content_type='text/plain', status=200)
        elif req.method.upper() == 'GET':
            return 'admin_user_edit.html', data

        # Close pressed: get back to user listing
        if req.args.get('close'):
            return req.redirect(req.href('admin/users/manage'))

        if req.args.get('deputy_name'):
            deputy = userstore.getUser(req.args.get('deputy_name').strip())
            resource = Resource('user', id=deputy.id)
            perm = PermissionCache(self.env, username=deputy.username)
            if perm.has_permission('USER_AUTHOR', resource):
                if(userstore.add_deputy(user.id, deputy.username)):
                    add_notice(req, _("Deputy "+deputy.username+" added."))
                    return_url = 'home/admin/users/manage?username='******'home/admin/users/manage?username='******'t have enough rights"))
                return_url = 'home/admin/users/manage?username='******'limitexceeded' in req.args:
            add_warning(req, _('Picture you tried to upload was too big. Try a smaller one'))

        # Update author if changed
        author_id = req.args.get('author_id', None)

        # If id field is empty but name is not: manual input
        if not author_id and req.args.get('author_text'):
            add_warning(req, _('Author cannot be found'))
            return 'admin_user_edit.html', data

        # Check set reset the author
        if author_id:
            author = userstore.getUserWhereId(int(author_id))
            if not author:
                add_warning(req, _('Author cannot be found'))
                return 'admin_user_edit.html', data

            # Check if author is valid: has permission to author?
            perm = PermissionCache(self.env, author.username)
            if 'USER_AUTHOR' not in perm:
                add_warning(req, _('User %s cannot work as an author (does not have USER_AUTHOR permissions)' % author))
                return self.back(req)

            user.author_id = author.id
            changes['author'] = author
        else:
            user.author_id = None

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

        old_mail = user.mail
        user.mail = req.args.get('email')
        if not user.mail:
            add_warning(req, _('Email address required'))
            return self.back(req)

        if old_mail != user.mail:
            changes['email'] = user.mail
            org_store = CQDEOrganizationStore.instance()
            # TODO: is this correct?
            # When changing email, reset organizations to which the user belongs in
            user.organization_keys = org_store.get_organization_keys(user) or None

        # Update password if changed
        password = req.args.get('password')
        if password:
            if not userstore.is_local(user):
                add_warning(req, _("Can't change password for user that uses external authentication method"))
                return self.back(req)

            if len(password) < 7:
                add_warning(req, _("Password must be at least 7 characters long - please provide longer password"))
                return self.back(req)

            if password != req.args.get('confirmpw'):
                add_warning(req, _("Password do not match - please check"))
                return self.back(req)

        user.givenName = req.args.get('first')
        user.mobile = req.args.get('mobile')

        # Set or reset account expiration date
        expiration_str = req.args.get('expires', '')
        if expiration_str:
            try:
                # Parse date and set expiration time in the end of the day
                expires = datetime.strptime(expiration_str, DATEFORMATS['py'])
                expires += timedelta(hours=23, minutes=59, seconds=59)

                # If changed
                if expires != user.expires:
                    user.expires = expires
                    changes['expiration_date'] = user.expires.strftime(DATEFORMATS['py'])

            except Exception:
                self.log.exception('Date formatting failed')
                add_warning(req, _('Non-recognized expiration format'))
                pass

        # Remove expiration date
        elif user.expires:
            changes['expiration_date'] = 'Never expires'
            user.expires = None

        # Update status if set
        status = int(req.args.get('status', 0))
        if status and status in userstore.USER_STATUS_LABELS.keys() and user.status != status:
            changes['status'] = userstore.USER_STATUS_LABELS[status]
            user.status = status

        if req.args.get('removeicon'):
            user.icon = None
        else:
            icon = req.args.get('icon')
            if not isinstance(icon, unicode) and icon.filename:
                user.createIcon(req.args.get('icon'))

        self.log.info('Saving changes to user: %s' % user)
        ok = userstore.updateUser(user)
        if ok and password:
            changes['password'] = password
            ok = userstore.updatePassword(user, password)

        if not ok:
            add_warning(req, _("Could not save changes"))

        add_notice(req, _("User %s updated" % username))

        # Notify user about changes via email?
        if req.args.get('notify'):
            data = {
                'user':user,
                'changed_by':changed_by,
                'changes':changes
            }

            try:
                enotify = EmailNotifier(self.env, "Account updated", data)
                enotify.template_name = 'account_edited.txt'
                enotify.notify(user.mail)
                add_notice(req, _("Notified user about the changes"))
            except TracError:
                add_warning(req, _("Failed to send email notification - user changed anyway"))

        # Check if user has still (after modification) permission to modify user
        # NOTE: req.perm cannot be used here because it is not updated yet
        #resource = Resource('user', id=user.id)
        #perm = PermissionCache(self.env, username=req.authname)
        #if perm.has_permission('USER_AUTHOR', resource):
        #    return self.back(req)
        if self.check_author_and_deputies(changed_by.id,
            user.author_id, userstore.get_deputies(user.id), req, user.id) == True:
            return_url = 'home/admin/users/manage?username='******'You have no longer permission to modify the account: %s' % user.username))
            return req.redirect(req.href('admin/users/manage'))