Esempio n. 1
0
 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))
Esempio n. 2
0
    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))
Esempio n. 3
0
 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))
Esempio n. 4
0
File: util.py Progetto: jun66j5/TraM
def is_authorised(authname, perms, env, permission=None, list_permission='PROJECT_ACCESS'):
    if not authname:
        authname = 'anonymous'
        perms = PermissionCache(env, authname)

    if not perms.has_permission(list_permission):
        return False

    if permission:
        return perms.has_permission(permission)

    return True
Esempio n. 5
0
    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))
Esempio n. 6
0
    def filter_subscriptions(self, event, subscriptions):
        action = '%s_VIEW' % event.realm.upper()

        for subscription in subscriptions:
            if event.realm in self.exception_realms:
                yield subscription
                continue

            sid, auth = subscription[1:3]
            # PermissionCache already takes care of sid = None
            if not auth:
                sid = 'anonymous'
            perm = PermissionCache(self.env, sid)
            resource_id = get_target_id(event.target)
            self.log.debug(
                'Checking *_VIEW permission on event for resource %s:%s'
                % (event.realm, resource_id)
            )
            if perm.has_permission(action) and action in perm(event.realm,
                                                              resource_id):
                yield subscription
            else:
                self.log.debug(
                    "Filtering %s because of %s rule" 
                    % (sid, self.__class__.__name__)
                )
Esempio n. 7
0
    def _send_index(self, environ, start_response):
        projects = []

        for env_name in os.listdir(self.path):
            env_path = os.path.join(self.path, env_name)
            try:
                env = open_environment(env_path)
                env_perm = PermissionCache(
                    PermissionSystem(env).get_user_permissions(
                        environ.get("REMOTE_USER", "anonymous")))

                if env_perm.has_permission('WIKI_VIEW'):
                    projects.append({
                        'name':
                        env.project_name,
                        'description':
                        env.project_description,
                        # XXX: get rid of the double / in the beginning
                        'href':
                        construct_url(environ, path_info="/" + env_name),
                    })
            except Exception:
                pass

        projects.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower()))
        start_response("200 OK", [('content-type', 'text/html')])
        return self.template.render({"projects": projects},
                                    format='xhtml',
                                    template="wsgiplugin.index")
Esempio n. 8
0
 def match(self, message):
     reporter = emailaddr2user(self.env, message['from'])
     reply_to_ticket = ReplyToTicket(self.env)
     
     perm = PermissionCache(self.env, reporter)        
     if not perm.has_permission('TICKET_ADD_HOURS'):
         return False
     return bool(reply_to_ticket.ticket(message))
Esempio n. 9
0
    def match(self, message):
        reporter = emailaddr2user(self.env, message['from'])
        reply_to_ticket = ReplyToTicket(self.env)

        perm = PermissionCache(self.env, reporter)
        if not perm.has_permission('TICKET_ADD_HOURS'):
            return False
        return bool(reply_to_ticket.ticket(message))
Esempio n. 10
0
 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))
Esempio n. 11
0
 def ticket_changed(self, ticket, comment, author, old_values):
     """Called when a ticket is modified.
     
     `old_values` is a dictionary containing the previous values of the
     fields that have changed.
     """
     perm = PermissionCache(self.env, author)
     if perm.has_permission('TICKET_ADD_HOURS'):
         self.add_hours_by_comment(comment, ticket.id, author)
Esempio n. 12
0
 def ticket_changed(self, ticket, comment, author, old_values):
     """Called when a ticket is modified.
     
     `old_values` is a dictionary containing the previous values of the
     fields that have changed.
     """
     perm = PermissionCache(self.env, author)
     if perm.has_permission('TICKET_ADD_HOURS'):
         self.add_hours_by_comment(comment, ticket.id, author)
Esempio n. 13
0
    def watch_hours(self, ticket):
        def readTicketValue(name, tipe, default=0):
            if ticket.values.has_key(name):
                return tipe(ticket.values[name] or default)
            else:
                cursor = self.env.get_db_cnx().cursor()
                cursor.execute(
                    "SELECT * FROM ticket_custom where ticket=%s and name=%s",
                    (ticket.id, name))
                val = cursor.fetchone()
                if val:
                    return tipe(val[2] or default)
                return default

        hours = readTicketValue("hours", convertfloat)
        totalHours = readTicketValue("totalhours", convertfloat)

        db = self.env.get_db_cnx()
        ticket_id = ticket.id
        cl = ticket.get_changelog()

        self.log.debug("found hours: " + str(hours))
        #self.log.debug("Dir_ticket:"+str(dir(ticket)))
        #self.log.debug("ticket.values:"+str(ticket.values))
        #self.log.debug("changelog:"+str(cl))

        most_recent_change = None
        if cl:
            most_recent_change = cl[-1]
            change_time = most_recent_change[0]
            author = most_recent_change[1]
        else:
            change_time = ticket.time_created
            author = ticket.values["reporter"]

        self.log.debug("Checking permissions")
        perm = PermissionCache(self.env, author)
        if not perm or not perm.has_permission("TIME_RECORD"):
            self.log.debug(
                "Skipping recording because no permission to affect time")
            if hours != 0:

                tup = (ticket_id, author, change_time, "hours")
                self.log.debug("deleting ticket change %s %s %s %s" % tup)
                try:
                    delete_ticket_change(self, ticket_id, author, change_time,
                                         "hours")
                except Exception, e:
                    self.log.debug("FAIL: %s" % e)
                self.log.debug("hours change deleted")
            return
Esempio n. 14
0
 def filter_subscriptions(self, event, subscriptions):
     action = '%s_VIEW'%event.realm.upper()
     for subscription in subscriptions:
         sid, auth = subscription[1:3]
         # PermissionCache already takes care of sid = None
         if not auth:
             sid = 'anonymous'
         perm = PermissionCache(self.env, sid)
         if event.realm in self.exception_realms or perm.has_permission(action):
             yield subscription
         else:
             self.log.debug(
                 "Filtering %s with realm %s because of rule: DefaultPermissionFilter"\
                 % (sid, event.realm)
             )
Esempio n. 15
0
    def watch_hours(self, ticket):
        def readTicketValue(name, tipe, default=0):
            if ticket.values.has_key(name):        
                return tipe(ticket.values[name] or default)
            else:
                cursor = self.env.get_db_cnx().cursor()
                cursor.execute("SELECT * FROM ticket_custom where ticket=%s and name=%s" , (ticket.id, name))
                val = cursor.fetchone()
                if val:
                    return tipe(val[2] or default)
                return default

        hours = readTicketValue("hours", convertfloat)
        totalHours = readTicketValue("totalhours", convertfloat)

        db = self.env.get_db_cnx()
        ticket_id = ticket.id
        cl = ticket.get_changelog()
        
        self.log.debug("found hours: "+str(hours ));
        #self.log.debug("Dir_ticket:"+str(dir(ticket)))
        #self.log.debug("ticket.values:"+str(ticket.values))
        #self.log.debug("changelog:"+str(cl))
    
        most_recent_change = None
        if cl:
            most_recent_change = cl[-1];
            change_time = most_recent_change[0]
            author = most_recent_change[1]
        else:
            change_time = ticket.time_created
            author = ticket.values["reporter"]

        self.log.debug("Checking permissions")
        perm = PermissionCache(self.env, author)
        if not perm or not perm.has_permission("TIME_RECORD"):
            self.log.debug("Skipping recording because no permission to affect time")
            if hours != 0:
                
                tup = (ticket_id, author, change_time, "hours")
                self.log.debug("deleting ticket change %s %s %s %s" % tup)
                try:
                    delete_ticket_change(self, ticket_id, author, change_time, "hours")
                except Exception, e:
                    self.log.debug("FAIL: %s" % e)
                self.log.debug("hours change deleted")
            return
Esempio n. 16
0
    def filter_subscriptions(self, event, subscriptions):
        action = 'ACCTMGR_USER_ADMIN'

        for subscription in subscriptions:
            if event.realm != 'acct_mgr':
                yield subscription
                continue

            # Make acct_mgr subscriptions available only for admins.
            sid, auth = subscription[1:3]
            # PermissionCache already takes care of sid = None
            if not auth:
                sid = 'anonymous'
            perm = PermissionCache(self.env, sid)
            if perm.has_permission(action):
                yield subscription
            else:
                self.log.debug("Filtering %s because of %s rule" %
                               (sid, self.__class__.__name__))
Esempio n. 17
0
    def filter_subscriptions(self, event, subscriptions):
        action = 'ACCTMGR_USER_ADMIN'

        for subscription in subscriptions:
            if event.realm != 'acct_mgr':
                yield subscription
                continue

            # Make acct_mgr subscriptions available only for admins.
            sid, auth = subscription[1:3]
            # PermissionCache already takes care of sid = None
            if not auth:
                sid = 'anonymous'
            perm = PermissionCache(self.env, sid)
            if perm.has_permission(action):
                yield subscription
            else:
                self.log.debug(
                    "Filtering %s because of %s rule"
                    % (sid, self.__class__.__name__)
                )
Esempio n. 18
0
    def process_request(self, req):
        parent_dir = os.path.dirname(self.env.path)
        #env_paths = dict([(filename, os.path.join(parent_dir, filename))
        #                  for filename in os.listdir(parent_dir)])
        projects = []
                          
        for env_name in os.listdir(parent_dir):
            env_path = os.path.join(parent_dir, env_name)
            
            # Don't list this environment
            if env_path == self.env.path:
                continue
            
            try:
                env = open_environment(env_path)

                try:
                    #self.log.debug(env.path)
                    env_perm = PermissionCache(env, req.authname)
                    #self.log.debug(env_perm.perms)
                    if env_perm.has_permission('PROJECT_VIEW'):
                        projects.append({
                            'name': env.project_name,
                            'description': env.project_description,
                            'href': req.href.projects(env_name),
                        })
                except Exception, e:
                    # Only show errors to admins to prevent excessive disclosure
                    if req.perm.has_permission('TRACFORGE_ADMIN'):
                        projects.append({
                            'name': env.project_name,
                            'description': to_unicode(e)
                        })
            except Exception, e:
                if req.perm.has_permission('TRACFORGE_ADMIN'):
                    projects.append({
                        'name': env_path,
                        'description': to_unicode(e),
                    })
Esempio n. 19
0
    def _send_index(self, environ, start_response):
        projects = []

        for env_name in os.listdir(self.path):
            env_path = os.path.join(self.path, env_name)
            try:
              env = open_environment(env_path)
              env_perm = PermissionCache(PermissionSystem(env).get_user_permissions(environ.get("REMOTE_USER", "anonymous")))

              if env_perm.has_permission('WIKI_VIEW'):
                  projects.append({
                      'name': env.project_name,
                      'description': env.project_description,
                      # XXX: get rid of the double / in the beginning
                      'href': construct_url(environ, path_info="/"+env_name),
                  })
            except Exception:
              pass

        projects.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower()))
        start_response("200 OK", [('content-type', 'text/html')])
        return self.template.render({"projects":projects}, format='xhtml', template = "wsgiplugin.index")
Esempio n. 20
0
    def filter_subscriptions(self, event, subscriptions):
        action = '%s_VIEW' % event.realm.upper()

        for subscription in subscriptions:
            if event.realm in self.exception_realms:
                yield subscription
                continue

            sid, auth = subscription[1:3]
            # PermissionCache already takes care of sid = None
            if not auth:
                sid = 'anonymous'
            perm = PermissionCache(self.env, sid)
            resource_id = get_target_id(event.target)
            self.log.debug(
                'Checking *_VIEW permission on event for resource %s:%s' %
                (event.realm, resource_id))
            if perm.has_permission(action) and action in perm(
                    event.realm, resource_id):
                yield subscription
            else:
                self.log.debug("Filtering %s because of %s rule" %
                               (sid, self.__class__.__name__))
Esempio n. 21
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'))
Esempio n. 22
0
    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))
Esempio n. 23
0
 def ticket_changed(self, ticket, comment, author, old_values):
     perm = PermissionCache(self.env, author)
     if perm.has_permission('TICKET_ADD_HOURS'):
         self.add_hours_by_comment(comment, ticket.id, author)
Esempio n. 24
0
 def test_no_endless_loop_if_permission_is_checked_with_string_instead_of_resource(
         self):
     perm = PermissionCache(self.env, 'foo')
     perm.has_permission('AGILO_BACKLOG_EDIT',
                         '%s:Sprint Backlog' % Realm.BACKLOG)
Esempio n. 25
0
 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))
Esempio n. 26
0
 def test_no_endless_loop_if_permission_is_checked_with_string_instead_of_resource(self):
     perm = PermissionCache(self.env, 'foo')
     perm.has_permission('AGILO_BACKLOG_EDIT', '%s:Sprint Backlog' % Realm.BACKLOG) 
Esempio n. 27
0
 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))
Esempio n. 28
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'))