    def user_model(self, user):
        """Get the JSON model for a User object

        User may be either a high-level User wrapper,
        or a low-level orm.User.
        """
        is_orm = False
        if isinstance(user, orm.User):
            if user.id in self.users:
                # if it's an 'active' user, it's in the users dict,
                # get the wrapper so we can get 'pending' state, etc.
                user = self.users[user.id]
            else:
                # don't create wrapper of low-level orm object
                is_orm = True

        if is_orm:
            # if it's not in the users dict,
            # we know it has no running servers
            running = False
            spawners = {}
        if not is_orm:
            running = user.running
            spawners = user.spawners

        include_stopped_servers = self.include_stopped_servers
        # TODO: we shouldn't fetch fields we can't read and then filter them out,
        # which may be wasted database queries
        # we should check and then fetch.
        # but that's tricky for e.g. server filters

        model = {
            'kind': 'user',
            'name': user.name,
            'admin': user.admin,
            'roles': [r.name for r in user.roles],
            'groups': [g.name for g in user.groups],
            'server': user.url if running else None,
            'pending': None,
            'created': isoformat(user.created),
            'last_activity': isoformat(user.last_activity),
            'auth_state': None,  # placeholder, filled in later
        }
        access_map = {
            'read:users': {
                'kind',
                'name',
                'admin',
                'roles',
                'groups',
                'server',
                'pending',
                'created',
                'last_activity',
            },
            'read:users:name': {'kind', 'name', 'admin'},
            'read:users:groups': {'kind', 'name', 'groups'},
            'read:users:activity': {'kind', 'name', 'last_activity'},
            'read:servers': {'kind', 'name', 'servers'},
            'read:roles:users': {'kind', 'name', 'roles', 'admin'},
            'admin:auth_state': {'kind', 'name', 'auth_state'},
        }
        allowed_keys = set()
        model = self._filter_model(
            model, access_map, user, kind='user', keys=allowed_keys
        )
        if model:
            if '' in spawners and 'pending' in allowed_keys:
                model['pending'] = spawners[''].pending

            servers = {}
            scope_filter = self.get_scope_filter('read:servers')
            for name, spawner in spawners.items():
                # include 'active' servers, not just ready
                # (this includes pending events)
                if (spawner.active or include_stopped_servers) and scope_filter(
                    spawner, kind='server'
                ):
                    servers[name] = self.server_model(spawner)

            if include_stopped_servers:
                # add any stopped servers in the db
                seen = set(servers.keys())
                if isinstance(user, orm.User):
                    # need high-level User wrapper for spawner model
                    # FIXME: this shouldn't be needed!
                    user = self.users[user]
                for name, orm_spawner in user.orm_spawners.items():
                    if name not in seen and scope_filter(orm_spawner, kind='server'):
                        servers[name] = self.server_model(orm_spawner, user=user)

            if "servers" in allowed_keys or servers:
                # omit servers if no access
                # leave present and empty
                # if request has access to read servers in general
                model["servers"] = servers

        return model
Get the JSON model for a User object

User may be either a high-level User wrapper,
or a low-level orm.User.
jupyterhub/apihandlers/base.py