Implementing Search User Feature for Admins

The users tab of admin panel of SUSI.AI provides a list of all users registered on SUSI. This helps admins to get an overview of users and also provides the admins option like change user roles and delete accounts. The list of users is displayed in a table which also uses pagination to handle larger number of users. But to find a particular user can be a difficult task if the user base is large. Therefore a feature to search for users by their email has been implement which searches for users on SUSI server and then sends the searched users to the client. In this post we will discuss both about the server and client side implementation of this feature.

On the server, the getUsers API is used to list all users based on pagination or search terms. For searching users we need to make the following request to this API,

/aaa/getUsers.json?access_token=go2ijgk5ijkmViAac2bifng3uthdZ&search=mario

 

The search parameter contains the value of the keyword which will be searched in emails of users by the server. All users are stored in the authorization.json files in the data directory on the server. First we need to fetch users list from this file and then create a list of all users. This is done by the DAO.getAuthorizedClients() method which returns a collection of authorized clients. This is converted into a list of strings and then into an array of strings where each entry is the email of the user.

Collection < ClientIdentity > authorized = DAO.getAuthorizedClients();

List < String > keysList = new ArrayList < String > ();

authorized.forEach(client - > keysList.add(client.toString()));

String[] keysArray = keysList.toArray(new String[keysList.size()]);

 

The ‘keysArray’ is iterated for each user and also searched for the search term and users with the search term are appended into the userList json array. The elements of keysArray has the substring ’email:’ at the beginning of their emails which needs to be sliced before searching for the keyword.

for (Client client: authorized) {

  String email = client.toString().substring(6);

  if (searchTerm == null || email.contains(searchTerm)) {

    JSONObject json = client.toJSON();

 

Once the iteration is completed the json array ‘userList’ is then send as the response to our query with a success message telling that we fetched all users with the search keyword in their emails.

else if (call.get("search", null) != null) {

  try {

    result.put("users", userList);

    result.put("accepted", true);

    result.put("message", "Success: Fetched all users with " + call.get("search", null) + " !");

    return new ServiceResponse(result);

  } catch (Exception e) {

    throw new APIException(422, "Requested user does not exists!");

  }

}

 

On the client side, a search input component with a placeholder telling to search by email is displayed which pass the search keyword to the handleSearch() function which handles the search queries.

<Search placeholder="Search by email" size="default" onSearch={value=> this.handleSearch(value)}

  />

 

The handleSearch function makes the API call and then process the response into the required format displayed on the screen.

handleSearch = value => {
  this.setState({

    search: true,

  });

  let url;

  url = `${urls.API_URL}/aaa/getUsers.json?access_token=${cookies.get(

'loggedIn',

)}&search=${value}`;

  $.ajax({

    url: url,

    dataType: 'jsonp',

    jsonpCallback: 'pvsdu',

    jsonp: 'callback',

    crossDomain: true,

  });

};

 

The response from the server is a json array with data about each user. This data is then processed into the format which is used in ant design tables using the code block below

success: function(response) {
    let userList = response.users;

    let users = [];

    userList.map((data, i) => {

      let devices = [];

      let keys = Object.keys(data.devices);

      keys.forEach(j => {

        let device = {

          macid: j,

          devicename: data.devices[j].name,

          room: data.devices[j].room,

          latitude: data.devices[j].geolocation.latitude,

          longitude: data.devices[j].geolocation.longitude,

        };

        devices.push(device);

      });

      let user = {

        serialNum: ++i,

        email: data.name,

        signup: data.signupTime,

        lastLogin: data.lastLoginTime,

        ipLastLogin: data.lastLoginIP,

        userRole: data.userRole,

        userName: data.userName,

        devices: devices,

      };

      if (data.confirmed) {

        user.confirmed = 'Activated';

      } else {

        user.confirmed = 'Not Activated';

      }

      users.push(user);

      return 1;

    });

 

Resources