Example #1
0
    def test_search_community_with_additional_fields_on_portal_with_query(
            self):
        """ This is the case when a client has customized user properties """
        login(self.portal, u'ulearn.testuser1')
        # We provide here the required initialization for a user custom properties catalog
        provideUtility(TestUserExtendedPropertiesSoupCatalogFactory(),
                       name='user_properties_exttest')
        api.portal.set_registry_record(
            name=
            'genweb.controlpanel.core.IGenwebCoreControlPanelSettings.user_properties_extender',
            value=u'user_properties_exttest')

        # Modify an user to accomodate new properties from extended catalog
        # Force it as we are not faking the extension of the user properties
        # (Plone side utility overriding blabla)
        add_user_to_catalog('ulearn.testuser1', {
            'position': u'Jefe',
            'unit_organizational': u'Finance'
        })

        users = searchUsersFunction(self.portal, self.request,
                                    'ulearn.testuser1')

        self.assertTrue(len(users['content']) == 1)
        self.assertEqual(users['content'][0]['id'], u'ulearn.testuser1')
        self.assertEqual(users['content'][0]['position'], u'Jefe')
        self.assertEqual(users['content'][0]['unit_organizational'],
                         u'Finance')
        self.assertEqual(users['content'][0]['telefon'], u'123456')

        logout()
Example #2
0
def UpdateUserPropertiesOnLogin(event):
    user = api.user.get_current()
    try:
        properties = get_all_user_properties(user)
        add_user_to_catalog(user, properties, overwrite=True)
    except:
        # To avoid testing test_functional code, since the
        # test_user doesn't have properties and stops the tests.
        pass
Example #3
0
    def render(self):
        context = aq_inner(self.context)
        all_user_properties = context.acl_users.mutable_properties.enumerateUsers()
        for user in all_user_properties:
            user.update(dict(username=user['id']))
            user.update(dict(fullname=user['title']))
            user_obj = api.user.get(user['id'])

            if user_obj:
                add_user_to_catalog(user_obj, user)
            else:
                print('No user found in user repository (LDAP) {}'.format(user['id']))

            print('Updated properties catalog for {}'.format(user['id']))
Example #4
0
    def test_user_properties_searchable_text(self):
        """ Test the searchable_text of the user_properties soup for make sure
            you can search on several properties at once.
        """
        self.create_default_test_users()
        reset_user_catalog()
        add_user_to_catalog(u'victor.fernandez', dict(fullname=u'Víctor Fernández de Alba', location='Nexus'))

        login(self.portal, u'ulearn.testuser1')

        soup = get_soup('user_properties', self.portal)
        self.assertTrue([r for r in soup.query(Eq('searchable_text', 'victor Nex*'))])
        logout()

        login(self.portal, 'admin')
        self.delete_default_test_users()
        logout()
Example #5
0
    def render(self, result_threshold=100):
        query = self.request.form.get('q', '')
        last_query = self.request.form.get('last_query', '')
        last_query_count = self.request.form.get('last_query_count', 0)
        if query:
            portal = api.portal.get()
            self.request.response.setHeader("Content-type", "application/json")
            soup = get_soup('user_properties', portal)
            searching_surname = len(re.match(r'^[^\ \.]+(?: |\.)*(.*?)$', query).groups()[0])

            normalized_query = query.replace('.', ' ') + '*'
            users_in_soup = [dict(id=r.attrs.get('username'),
                                  displayName=r.attrs.get('fullname'))
                                  for r in soup.query(Or(Eq('username', normalized_query),
                                                         Eq('fullname', normalized_query)))]
            too_much_results = len(users_in_soup) > result_threshold

            is_useless_request = query.startswith(last_query) and len(users_in_soup) == last_query_count

            if is_useless_request and (not too_much_results or searching_surname):
                current_user = api.user.get_current()
                oauth_token = current_user.getProperty('oauth_token', '')

                maxclient, settings = getUtility(IMAXClient)()
                maxclient.setActor(current_user.getId())
                maxclient.setToken(oauth_token)

                max_users = maxclient.people.get(qs={'limit': 0, 'username': query})
                users_in_max = [dict(id=user.get('username'), displayName=user.get('displayName')) for user in max_users]

                for user in users_in_max:
                    add_user_to_catalog(user['id'], dict(displayName=user['displayName']))

                return json.dumps(dict(results=users_in_max,
                                       last_query=query,
                                       last_query_count=len(users_in_max)))
            else:
                return json.dumps(dict(results=users_in_soup,
                                       last_query=query,
                                       last_query_count=len(users_in_soup)))

        else:
            return json.dumps(dict(error='No query found',
                                   last_query='',
                                   last_query_count=0))
Example #6
0
    def test_user_legit_mode(self):
        """
        """
        self.create_default_test_users()
        reset_user_catalog()
        # Add a legit user
        add_user_to_catalog(u'victor.fernandez', dict(fullname=u'Víctor'))
        normalized_query = 'victor fer*'
        soup = get_soup('user_properties', self.portal)

        # Search for it via the searchable_text
        result = [r for r in soup.query(Eq('searchable_text', normalized_query))]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez')
        self.assertEqual(len(result), 1)

        # Add a non legit user from the initial set
        add_user_to_catalog(u'victor.fernandez.1', dict(fullname=u'Víctor'), notlegit=True)

        # The result is still the legit one alone
        result = [r for r in soup.query(Eq('searchable_text', normalized_query))]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez')
        self.assertEqual(len(result), 1)

        # The non legit only can be accessed directly by querying the notlegit
        # index and the legit one does not show, of course
        result = [r for r in soup.query(Eq('notlegit', True))]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez.1')
        self.assertEqual(len(result), 1)

        # The non legit only can be accessed directly by querying the fields
        # directly
        result = [r for r in soup.query(And(Or(Eq('username', normalized_query), Eq('fullname', normalized_query)), Eq('notlegit', True)))]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez.1')
        self.assertEqual(len(result), 1)

        # If the non legit became legit at some point of time via a subscriber
        api.user.get('victor.fernandez.1').setMemberProperties(mapping={'fullname': u'Test', 'location': u'Barcelona', 'telefon': u'654321 123 123'})

        # Then it does not show as not legit
        result = [r for r in soup.query(And(Or(Eq('username', normalized_query), Eq('fullname', normalized_query)), Eq('notlegit', True)))]
        self.assertEqual(len(result), 0)

        # And it shows as legit
        result = [r for r in soup.query(Eq('searchable_text', normalized_query))]
        self.assertEqual(len(result), 2)
Example #7
0
    def PUT(self):
        """
            Modify displayName user

            /api/people/{username}

            data = {'displayName':'Nom Cognom'}

        """
        existing_user = api.user.get(username=self.params['username'].lower())
        maxclient, settings = getUtility(IMAXClient)()
        maxclient.setActor(settings.max_restricted_username)
        maxclient.setToken(settings.max_restricted_token)

        if existing_user:
            if 'displayName' in self.params:
                # Update portal membership user properties
                existing_user.setMemberProperties(
                    {'fullname': self.params['displayName']})
                properties = get_all_user_properties(existing_user)
                add_user_to_catalog(existing_user, properties, overwrite=True)
                username = self.params['username'].lower()
                # Update max
                maxclient.people[username].put(
                    displayName=properties['fullname'])
                status = maxclient.last_response_code
            else:
                status = 500
        else:
            status = 404

        if status == 404:
            return ApiResponse.from_string('User {} not found'.format(
                self.params['username'].lower()),
                                           code=status)
        elif status == 200:
            return ApiResponse.from_string('User {} updated'.format(
                self.params['username'].lower()),
                                           code=status)
        elif status == 500:
            return ApiResponse.from_string(
                'User {} not updated. Not displayName.'.format(
                    self.params['username'].lower()),
                code=status)
Example #8
0
    def test_user_properties_searchable_text(self):
        """ Test the searchable_text of the user_properties soup for make sure
            you can search on several properties at once.
        """
        self.create_default_test_users()
        reset_user_catalog()
        add_user_to_catalog(
            u'victor.fernandez',
            dict(fullname=u'Víctor Fernández de Alba', location='Nexus'))

        login(self.portal, u'ulearn.testuser1')

        soup = get_soup('user_properties', self.portal)
        self.assertTrue(
            [r for r in soup.query(Eq('searchable_text', 'victor Nex*'))])
        logout()

        login(self.portal, 'admin')
        self.delete_default_test_users()
        logout()
Example #9
0
    def test_search_community_with_additional_fields_on_portal_with_query(self):
        """ This is the case when a client has customized user properties """
        login(self.portal, u'ulearn.testuser1')
        # We provide here the required initialization for a user custom properties catalog
        provideUtility(TestUserExtendedPropertiesSoupCatalogFactory(), name='user_properties_exttest')
        api.portal.set_registry_record(name='genweb.controlpanel.core.IGenwebCoreControlPanelSettings.user_properties_extender', value=u'user_properties_exttest')

        # Modify an user to accomodate new properties from extended catalog
        # Force it as we are not faking the extension of the user properties
        # (Plone side utility overriding blabla)
        add_user_to_catalog('ulearn.testuser1', {'position': u'Jefe', 'unit_organizational': u'Finance'})

        users = searchUsersFunction(self.portal, self.request, 'ulearn.testuser1')

        self.assertTrue(len(users['content']) == 1)
        self.assertEqual(users['content'][0]['id'], u'ulearn.testuser1')
        self.assertEqual(users['content'][0]['position'], u'Jefe')
        self.assertEqual(users['content'][0]['unit_organizational'], u'Finance')
        self.assertEqual(users['content'][0]['telefon'], u'123456')

        logout()
Example #10
0
    def test_user_search_on_acl(self):
        """
            cas 1: Primer caràcter (només 1) is_useless_request == False too_much_results ? searching_surname == False
            cas 2.1: Segona lletra en endavant i not searching_surname i is_useless_request i too_much_results ==> soup
            cas 2.1: Segona lletra en endavant i not searching_surname i is_useless_request i not too_much_results ==> MAX
            cas 2.2: Segona lletra en endavant i not searching_surname i not is_useless_request ==> Seguim filtrant query soup
            cas 3: Segona lletra  en endavant i searching_surname i not is_useless_request ==> soup
            cas 3: Segona lletra  en endavant i searching_surname i is_useless_request ==> MAX

            First request, no additional last_query nor last_query_count
            Create a bunch of users into the system, but clearing the catalog
            Only one remains
        """
        self.create_default_test_users()
        reset_user_catalog()
        add_user_to_catalog(u'victor.fernandez', dict(fullname=u'Víctor'))

        login(self.portal, u'ulearn.testuser1')

        search_view = getMultiAdapter((self.portal, self.request),
                                      name='omega13usersearch')
        self.request.form = dict(q='v')
        result = search_view.render()
        result = json.loads(result)
        self.assertEqual(result['last_query_count'], 1)
        self.assertEqual(result['last_query'], 'v')

        # Force the search to be useless to force a MAX update
        self.request.form = dict(q='victor.fer',
                                 last_query='v',
                                 last_query_count=1)
        result = search_view.render()
        result = json.loads(result)

        self.assertTrue(result['last_query_count'] > 5)
        self.assertEqual(result['last_query'], 'victor.fer')

        soup = get_soup('user_properties', self.portal)
        self.assertTrue(
            len([r for r in soup.query(Eq('username', 'victor fer*'))]) > 5)

        # Amb un altre usuari (janet)
        add_user_to_catalog(u'janet.dura', dict(fullname=u'Janet'))
        self.request.form = dict(q='janet', last_query='', last_query_count=0)
        result = search_view.render()
        result = json.loads(result)

        self.assertEqual(result['last_query_count'], 1)
        self.assertEqual(result['results'], [{
            u'displayName': u'Janet',
            u'id': u'janet.dura'
        }])

        self.request.form = dict(q='janeth',
                                 last_query='janet',
                                 last_query_count=1)
        result = search_view.render()
        result = json.loads(result)
        self.assertEqual(result['last_query_count'], 0)

        # Freeze this part as we cannot rely in that user being always there
        # self.request.form = dict(q='janeth.tosca', last_query='janeth', last_query_count=0)
        # result = search_view.render()
        # result = json.loads(result)

        # self.assertEqual(result['last_query_count'], 1)
        # self.assertEqual(result['results'], [{"displayName": "janeth.toscana", "id": "janeth.toscana"}])

        logout()

        login(self.portal, 'admin')
        self.delete_default_test_users()
        logout()
Example #11
0
def update_user_properties_hook(user, event):
    """ This subscriber hooks on user creation and adds user properties to the
        soup-based catalog for later searches
    """

    add_user_to_catalog(user, event.properties, overwrite=True)
Example #12
0
def create_user_hook(user, event):
    """ This subscriber hooks on user creation and adds user properties to the
        soup-based catalog for later searches
    """
    add_user_to_catalog(user)
Example #13
0
    def POST(self):
        """
            Syncs user local registry with remote ldap attributes
        """
        maxclient, settings = getUtility(IMAXClient)()
        maxclient.setActor(settings.max_restricted_username)
        maxclient.setToken(settings.max_restricted_token)
        users = self.params['users']

        notfound_errors = []
        properties_errors = []
        max_errors = []
        users_sync = []
        for userid in users:
            username = userid.lower()
            logger.info(
                '- API REQUEST /api/people/sync: Synchronize user {}'.format(
                    username))
            user_memberdata = api.user.get(username=username)
            try:
                plone_user = user_memberdata.getUser()
            except:
                logger.info(
                    '- API REQUEST /api/people/sync: ERROR sync user {}'.
                    format(username))
                notfound_errors.append(username)
                continue

            # Delete user cache
            for prop in plone_user.getOrderedPropertySheets():
                try:
                    ldap = prop
                    ldap._invalidateCache(plone_user)
                    plone_user._getPAS().ZCacheable_invalidate(
                        view_name='_findUser-' + username)
                    ldap._getLDAPUserFolder(plone_user)._expireUser(plone_user)
                    break
                except:
                    continue

            response = {}
            try:
                user_memberdata = api.user.get(username=username)
                plone_user = user_memberdata.getUser()
            except:
                notfound_errors.append(username)
                logger.error(
                    'User {} cannot be found in LDAP repository'.format(
                        username))
            else:
                try:
                    properties = get_all_user_properties(plone_user)
                    add_user_to_catalog(plone_user, properties, overwrite=True)
                except:
                    logger.error(
                        'Cannot update properties catalog for user {}'.format(
                            username))
                    properties_errors.append(username)

                try:
                    fullname = properties.get('fullname', '')
                    maxclient.people.post(username=username,
                                          displayName=fullname)

                    # If user hasn't been created right now, update displayName
                    if maxclient.last_response_code == 200:
                        maxclient.people[username].put(displayName=fullname)
                    users_sync.append(username)
                    logger.info(
                        '- API REQUEST /api/people/sync: OK sync user {}'.
                        format(username))
                except:
                    logger.error(
                        'User {} couldn\'t be created or updated on max'.
                        format(username))
                    max_errors.append(username)

        response = {}
        if notfound_errors:
            response['not_found'] = notfound_errors
        if properties_errors:
            response['properties_errors'] = properties_errors
        if max_errors:
            response['max_errors'] = max_errors
        response['synced_users'] = users_sync

        return ApiResponse(response)
Example #14
0
    def render(self, result_threshold=100):
        query = self.request.form.get('q', '')
        last_query = self.request.form.get('last_query', '')
        last_query_count = self.request.form.get('last_query_count', 0)
        if query:
            portal = api.portal.get()
            self.request.response.setHeader('Content-type', 'application/json')
            soup = get_soup('user_properties', portal)
            searching_surname = len(re.match(r'^[^\ \.]+(?: |\.)*(.*?)$', query).groups()[0])

            if isinstance(query, str):
                query = query.decode('utf-8')

            normalized_query = unicodedata.normalize('NFKD', query).encode('ascii', errors='ignore')
            normalized_query = normalized_query.replace('.', ' ') + '*'

            def user_entry(record):
                username = record.attrs.get('username')
                fullname = record.attrs.get('fullname')
                return dict(
                    id=username,
                    displayName=fullname if fullname else username
                )

            def searchable_text():
                return soup.query(Eq('searchable_text', normalized_query))

            def not_legit_users():
                return soup.query(And(
                    Or(
                        Eq('username', normalized_query),
                        Eq('fullname', normalized_query)
                    ),
                    Eq('notlegit', True)
                ))

            users_in_soup = [user_entry(r) for r in searchable_text()] + \
                            [user_entry(r) for r in not_legit_users()]

            too_much_results = len(users_in_soup) > result_threshold

            is_useless_request = query.startswith(last_query) and len(users_in_soup) == int(last_query_count)

            if is_useless_request and (not too_much_results or searching_surname):
                current_user = api.user.get_current()
                oauth_token = current_user.getProperty('oauth_token', '')

                maxclient, settings = getUtility(IMAXClient)()
                maxclient.setActor(current_user.getId())
                maxclient.setToken(oauth_token)

                max_users = maxclient.people.get(qs={'limit': 0, 'username': query})
                users_in_max = [dict(id=user.get('username'), displayName=user.get('displayName')) for user in max_users]

                for user in users_in_max:
                    add_user_to_catalog(user['id'], dict(displayName=user['displayName']), notlegit=True)

                return json.dumps(dict(results=users_in_max,
                                       last_query=query,
                                       last_query_count=len(users_in_max)))
            else:
                return json.dumps(dict(results=users_in_soup,
                                       last_query=query,
                                       last_query_count=len(users_in_soup)))

        else:
            return json.dumps(dict(error='No query found',
                                   last_query='',
                                   last_query_count=0))
Example #15
0
    def test_user_search_on_acl(self):
        """
            cas 1: Primer caràcter (només 1) is_useless_request == False too_much_results ? searching_surname == False
            cas 2.1: Segona lletra en endavant i not searching_surname i is_useless_request i too_much_results ==> soup
            cas 2.1: Segona lletra en endavant i not searching_surname i is_useless_request i not too_much_results ==> MAX
            cas 2.2: Segona lletra en endavant i not searching_surname i not is_useless_request ==> Seguim filtrant query soup
            cas 3: Segona lletra  en endavant i searching_surname i not is_useless_request ==> soup
            cas 3: Segona lletra  en endavant i searching_surname i is_useless_request ==> MAX

            First request, no additional last_query nor last_query_count
            Create a bunch of users into the system, but clearing the catalog
            Only one remains
        """
        self.create_default_test_users()
        reset_user_catalog()
        add_user_to_catalog(u'victor.fernandez', dict(fullname=u'Víctor'))

        login(self.portal, u'ulearn.testuser1')

        search_view = getMultiAdapter((self.portal, self.request), name='omega13usersearch')
        self.request.form = dict(q='v')
        result = search_view.render()
        result = json.loads(result)
        self.assertEqual(result['last_query_count'], 1)
        self.assertEqual(result['last_query'], 'v')

        # Force the search to be useless to force a MAX update
        self.request.form = dict(q='victor.fer', last_query='v', last_query_count=1)
        result = search_view.render()
        result = json.loads(result)

        self.assertTrue(result['last_query_count'] > 5)
        self.assertEqual(result['last_query'], 'victor.fer')

        soup = get_soup('user_properties', self.portal)
        self.assertTrue(len([r for r in soup.query(Eq('username', 'victor fer*'))]) > 5)

        # Amb un altre usuari (janet)
        add_user_to_catalog(u'janet.dura', dict(fullname=u'Janet'))
        self.request.form = dict(q='janet', last_query='', last_query_count=0)
        result = search_view.render()
        result = json.loads(result)

        self.assertEqual(result['last_query_count'], 1)
        self.assertEqual(result['results'], [{u'displayName': u'Janet', u'id': u'janet.dura'}])

        self.request.form = dict(q='janeth', last_query='janet', last_query_count=1)
        result = search_view.render()
        result = json.loads(result)
        self.assertEqual(result['last_query_count'], 0)

        # Freeze this part as we cannot rely in that user being always there
        # self.request.form = dict(q='janeth.tosca', last_query='janeth', last_query_count=0)
        # result = search_view.render()
        # result = json.loads(result)

        # self.assertEqual(result['last_query_count'], 1)
        # self.assertEqual(result['results'], [{"displayName": "janeth.toscana", "id": "janeth.toscana"}])

        logout()

        login(self.portal, 'admin')
        self.delete_default_test_users()
        logout()
Example #16
0
    def test_user_legit_mode(self):
        """
        """
        self.create_default_test_users()
        reset_user_catalog()
        # Add a legit user
        add_user_to_catalog(u'victor.fernandez', dict(fullname=u'Víctor'))
        normalized_query = 'victor fer*'
        soup = get_soup('user_properties', self.portal)

        # Search for it via the searchable_text
        result = [
            r for r in soup.query(Eq('searchable_text', normalized_query))
        ]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez')
        self.assertEqual(len(result), 1)

        # Add a non legit user from the initial set
        add_user_to_catalog(u'victor.fernandez.1',
                            dict(fullname=u'Víctor'),
                            notlegit=True)

        # The result is still the legit one alone
        result = [
            r for r in soup.query(Eq('searchable_text', normalized_query))
        ]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez')
        self.assertEqual(len(result), 1)

        # The non legit only can be accessed directly by querying the notlegit
        # index and the legit one does not show, of course
        result = [r for r in soup.query(Eq('notlegit', True))]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez.1')
        self.assertEqual(len(result), 1)

        # The non legit only can be accessed directly by querying the fields
        # directly
        result = [
            r for r in soup.query(
                And(
                    Or(Eq('username', normalized_query),
                       Eq('fullname', normalized_query)), Eq('notlegit',
                                                             True)))
        ]
        self.assertEqual(result[0].attrs['id'], 'victor.fernandez.1')
        self.assertEqual(len(result), 1)

        # If the non legit became legit at some point of time via a subscriber
        api.user.get('victor.fernandez.1').setMemberProperties(
            mapping={
                'fullname': u'Test',
                'location': u'Barcelona',
                'telefon': u'654321 123 123'
            })

        # Then it does not show as not legit
        result = [
            r for r in soup.query(
                And(
                    Or(Eq('username', normalized_query),
                       Eq('fullname', normalized_query)), Eq('notlegit',
                                                             True)))
        ]
        self.assertEqual(len(result), 0)

        # And it shows as legit
        result = [
            r for r in soup.query(Eq('searchable_text', normalized_query))
        ]
        self.assertEqual(len(result), 2)
Example #17
0
    def render(self, result_threshold=100):
        query = self.request.form.get('q', '')
        last_query = self.request.form.get('last_query', '')
        last_query_count = self.request.form.get('last_query_count', 0)
        if query:
            portal = api.portal.get()
            self.request.response.setHeader('Content-type', 'application/json')
            soup = get_soup('user_properties', portal)
            searching_surname = len(
                re.match(r'^[^\ \.]+(?: |\.)*(.*?)$', query).groups()[0])

            if isinstance(query, str):
                query = query.decode('utf-8')

            normalized_query = unicodedata.normalize('NFKD', query).encode(
                'ascii', errors='ignore')
            normalized_query = normalized_query.replace('.', ' ') + '*'

            def user_entry(record):
                username = record.attrs.get('username')
                fullname = record.attrs.get('fullname')
                return dict(id=username,
                            displayName=fullname if fullname else username)

            def searchable_text():
                return soup.query(Eq('searchable_text', normalized_query))

            def not_legit_users():
                return soup.query(
                    And(
                        Or(Eq('username', normalized_query),
                           Eq('fullname', normalized_query)),
                        Eq('notlegit', True)))

            users_in_soup = [user_entry(r) for r in searchable_text()] + \
                            [user_entry(r) for r in not_legit_users()]

            too_much_results = len(users_in_soup) > result_threshold

            is_useless_request = query.startswith(last_query) and len(
                users_in_soup) == int(last_query_count)

            if is_useless_request and (not too_much_results
                                       or searching_surname):
                current_user = api.user.get_current()
                oauth_token = current_user.getProperty('oauth_token', '')

                maxclient, settings = getUtility(IMAXClient)()
                maxclient.setActor(current_user.getId())
                maxclient.setToken(oauth_token)

                max_users = maxclient.people.get(qs={
                    'limit': 0,
                    'username': query
                })
                users_in_max = [
                    dict(id=user.get('username'),
                         displayName=user.get('displayName'))
                    for user in max_users
                ]

                for user in users_in_max:
                    add_user_to_catalog(user['id'],
                                        dict(displayName=user['displayName']),
                                        notlegit=True)

                return json.dumps(
                    dict(results=users_in_max,
                         last_query=query,
                         last_query_count=len(users_in_max)))
            else:
                return json.dumps(
                    dict(results=users_in_soup,
                         last_query=query,
                         last_query_count=len(users_in_soup)))

        else:
            return json.dumps(
                dict(error='No query found', last_query='',
                     last_query_count=0))