🎉 New release for Pusher Chatkit - Webhooks! Extend your in-app chat functionality
Hide
Products
chatkit_full-logo

Extensible API for in-app chat

channels_full-logo

Build scalable realtime features

beams_full-logo

Programmatic push notifications

Developers

Docs

Read the docs to learn how to use our products

Tutorials

Explore our tutorials to build apps with Pusher products

Support

Reach out to our support team for help and advice

Sign in
Sign up

Implement Chatkit roles and permissions in a React Native chat app - Part 1: Setting permissions on the server

  • Wern Ancheta
May 28th, 2019
You will need a good understanding of React Native, and Node 11+ and Yarn 1+ installed on your machine.

In this tutorial, we will be building our own web app for setting the roles and permissions that will be used in the mobile app.

This is a two-part series, we’ll be looking at how you can use both the server and client SDK’s of Chatkit to build a React Native chat app which implements roles and permissions.

Prerequisites

You will need a good level of understanding of React Native, and familiarity with building and running apps in your development environment to follow this tutorial.

You will also need to have basic knowledge of Node.js.

The following package versions are used in this tutorial:

  • Node 11.2.0
  • Yarn 1.13.0
  • React Native 0.59.5

If you encounter any issues getting the app to work, try switching to the ones above.

We’re using Chatkit in this tutorial, so you need to have a Chatkit account to create a new app instance.

App overview

The web app that we’ll be creating will have the following functionality:

  • Create rooms.
  • Create users.
  • View users in a specific room.
  • Add user to a room.
  • Create a role.
  • Assign a role to a user.

When the user opens the page, there are three buttons: Create Room, Create Role, and Create User. Clicking those buttons will open the corresponding modal that will allow the user to enter the details:

Once a room is created, it’s appended to the table of rooms right below those buttons:

From there, the user can either view or add users to that room. Clicking the View Users button will show the list of users in that room:

Adding a user will append a new row to the users table:

Lastly, from the users table, the user can click on the Set Role button to assign a specific role to the user:

You can view the code on this GitHub repo.

Bootstrapping the app

As you already know, things move quite fast in React Native. So to ensure compatibility, I created a repo which already has all the dependencies in the package.json file:

    git clone https://github.com/anchetaWern/RNChatkitRoles
    git checkout starter

We won’t be working on the React Native app in this part of the series though, so go inside the server directory and install the dependencies in there:

    cd server
    yarn

Lastly, update the server/.env file with your Chatkit credentials.

    CHATKIT_INSTANCE_LOCATOR_ID="YOUR CHATKIT APP INSTANCE (omit v1:us1:)"
    CHATKIT_SECRET_KEY="YOUR CHATKIT SECRET"

Building the app

Now we’re ready to work on the server code. We’ll start by updating the server/index.js file. It already has a few codes in there for handling the Chatkit authentication, getting the user’s data, and getting the rooms. The first thing we do is import the libraries we need:

    // server/index.js

    // ...

    const Chatkit = require("@pusher/chatkit-server");

    // add these:
    const mustacheExpress = require("mustache-express"); // for templating
    const randomId = require("random-id"); // for generating random IDs

Next, set Mustache as the templating engine to be used by Express:

    // initialize Express

    // ..

    app.use(cors());

    // add these:
    app.use(express.static('public'));

    app.engine('mustache', mustacheExpress());
    app.set('view engine', 'mustache'); // set mustache as the templating engine
    app.set('views', __dirname + '/views'); // set location of mustache templates

Next, add the route for serving the page that the user will use to perform the different tasks mentioned earlier. This makes use of the getRooms method to get all the rooms in this specific Chatkit instance:

    app.get("/users-console", async (req, res) => {
      try {
        const chatkit_rooms = await chatkit.getRooms({ includePrivate: true }); // private rooms aren't included by default
        res.render('users-console', { title: "Users Console", rooms: chatkit_rooms });
      } catch (get_rooms_err) {
        console.log("error getting rooms: ", get_rooms_err);
      }
    });

Next, create the Mustache template (server/views/user-console.mustache):

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8"/>
      <title>{{title}}</title>
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

      <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.1.2/handlebars.min.js"></script>

      <!-- pre-compiled Handlebars templates -->
      <script src="/templates/option-users.js"></script>
      <script src="/templates/table-users.js"></script>
      <script src="/templates/option-roles.js"></script>
      <script src="/templates/checkbox-permissions.js"></script>
      <script src="/templates/table-rooms.js"></script>
    </head>
    <body>
      <div class="container">
        <div class="row align-items-center">
          <div class="col col-lg-12">
            <h1>{{title}}</h1>
            <div class="mt-5">
              <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#create-room-modal">
                Create Room
              </button>

              <button type="button" class="btn btn-success" data-toggle="modal" data-target="#create-user-modal">
                Create User
              </button>

              <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#create-role-modal">
                Create Role
              </button>
            </div>

            <div class="mt-4">
              <table class="table">
                <thead>
                  <tr>
                    <th>Room</th>
                    <th>Users</th>
                    <th>Add User</th>
                  </tr>
                </thead>
                <tbody id="rooms-table-rows">
                  {{#rooms}}
                  <tr>
                    <td>
                      {{name}}
                    </td>
                    <td>
                      <button type="button" class="btn btn-sm btn-warning view-users" data-id="{{id}}" data-name="{{name}}">View Users</button>
                    </td>
                    <td>
                      <button type="button" class="btn btn-sm btn-info add-user" data-id="{{id}}" data-name="{{name}}">Add User</button>
                    </td>
                  </tr>
                  {{/rooms}}
                </tbody>
              </table>
            </div>

            <div class="mt-5 d-none" id="users-container">
              <h4><span class="current-room"></span> Users</h4>
              <table class="table" id="users-table">
                <thead>
                  <tr>
                    <th>User</th>
                    <th>Set Role</th>
                  </tr>
                </thead>
                <tbody id="users-table-rows">

                </tbody>
              </table>
            </div>

            <div class="modal fade" id="create-user-modal" tabindex="-1">
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Create User</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>

                  <div class="modal-body">
                    <form>
                      <div class="form-group">
                        <label for="user_name">User name</label>
                        <input type="text" class="form-control" id="user_name" name="user_name">
                      </div>
                    </form>
                  </div>

                  <div class="modal-footer">
                    <button type="button" id="create-user" class="btn btn-primary">Create</button>
                  </div>
                </div>
              </div>
            </div>

            <div class="modal fade" id="create-room-modal" tabindex="-1">
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Create Room</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>

                  <div class="modal-body">
                    <form>
                      <div class="form-group">
                        <label for="room_name">Room name</label>
                        <input type="text" class="form-control" id="room_name" name="room_name">
                      </div>
                      <div class="form-check">
                        <input type="checkbox" class="form-check-input" id="is_private_room" name="is_private_room">
                        <label class="form-check-label" for="is_private_room">Is Private?</label>
                      </div>
                    </form>
                  </div>

                  <div class="modal-footer">
                    <button type="button" id="create-room" class="btn btn-primary">Create</button>
                  </div>
                </div>
              </div>
            </div>

            <div class="modal fade" id="add-user-to-room-modal" tabindex="-1">
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Add User to Room (<span class="current-room"></span>)</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>

                  <div class="modal-body">
                    <form>
                      <div class="form-group">
                        <label for="user_to_add">User</label>
                        <select class="form-control" id="user_to_add" name="user_to_add">

                        </select>
                      </div>
                    </form>
                  </div>

                  <div class="modal-footer">
                    <button type="button" id="add-user-to-room" class="btn btn-primary">Add</button>
                  </div>
                </div>
              </div>
            </div>

            <div class="modal fade" id="create-role-modal" tabindex="-1">
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Create role</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>

                  <div class="modal-body">
                    <form>
                      <div class="form-group">
                        <label for="role_name">Role name</label>
                        <input type="text" class="form-control" id="role_name" name="role_name">
                      </div>

                      <div id="permissions-container"></div>
                    </form>
                  </div>

                  <div class="modal-footer">
                    <button type="button" id="create-role" class="btn btn-primary">Create</button>
                  </div>
                </div>
              </div>
            </div>

            <div class="modal fade" id="assign-roles-modal" tabindex="-1">
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Assign role to user [<span class="current-user"></span>] on room [<span class="current-room"></span>]</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>

                  <div class="modal-body">
                    <form>
                      <div class="form-group">
                        <label for="roles">Roles</label>
                        <select class="form-control" id="roles" name="roles">

                        </select>
                      </div>

                      <div id="role-permissions"></div>

                    </form>
                  </div>

                  <div class="modal-footer">
                    <button type="button" id="assign-role-to-user" class="btn btn-primary">Assign Role</button>
                  </div>
                </div>
              </div>
            </div>

          </div>
        </div>
      </div>

      <script src="https://code.jquery.com/jquery-3.4.0.min.js"></script>

      <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
      <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
      <script src="/js/user-console.js"></script>

    </body>
    </html>

From the code above, you can see all the elements that were mentioned in the app overview earlier. We’re using Bootstrap 4 for creating nice looking UI, jQuery for handling DOM events, and Handlebars for client-side templating.

If you’re wondering why we use Handlebars instead of Mustache, it’s because Mustache becomes a headache when you use it on both the server and client side. Basically, what happens is that the server will try to replace the template variables that are supposed to be parsed by the client-side version of Mustache. So if there aren’t any values assigned from the server, the template variable will just be rendered as an empty string. Using Handlebars helps us avoid this problem because it allows us to pre-compile the templates. Which means that the server-side Mustache won’t be able to interfere. Later on in the Running the app section, I’ll show you how you can compile the Handlebars templates.

Next, we move on to the client-side code. Note that we will be switching between the client-side and server-side code quite often, so be sure to watch the filenames at the beginning of each code block.

Start by creating the variables that we will be using throughout the script. In this app, we won’t be using the full list of permissions available to Chatkit. Instead, we only have a select few which we will implement in the mobile app:

    // server/public/js/user-console.js

    var current_room_id; // the id of the currently selected room (when the view user or add user button is clicked)
    var current_user_id; // the id of the user to assign to a specific role
    var current_user_name; // the name of the user to assign to a specific role
    var instance_roles = []; // the roles in this specific Chatkit app instance

    // a few selected permissions that can be set in this specific app
    var permissions = ['room:join', 'room:leave', 'room:members:add', 'room:members:remove', 'file:create', 'file:get', 'room:messages:get', 'message:create'];
    var permissions_html = Handlebars.templates\["checkbox-permissions"\]({ 'permissions': permissions }); // generate HTML containing the permissions data
    $('#permissions-container').html(permissions_html);

Here’s the the template for rendering the list of permissions. This will both be used when creating a new role and assigning a role to a user:

    <!-- server/templates/checkbox-permissions.handlebars -->
    <label>Permissions</label>
    {{#each permissions}}
    <div class="form-check">
      <input type="checkbox" class="form-check-input" name="permission" id="{{.}}" value="{{.}}">
      <label class="form-check-label" for="{{.}}">{{.}}</label>
    </div>
    {{/each}}

Create room

Next, add the code for sending the request to the server to create the room. The server responds with the list of updated rooms so we supply it as the data for the rooms template to refresh the rooms table:

    $('#create-room').click(function(){
      var room_name = $('#room_name').val();
      var is_private = $('#is_private_room').is(':checked');

      $.post(
        "/create-room",
        {
          'room_name': room_name,
          'is_private': is_private
        },
        function(rooms) {
          // refresh the rooms table
          var rooms_html = Handlebars.templates\["table-rooms"\]({ 'rooms': rooms });
          $('#rooms-table-rows').html(rooms_html);
        }
      );

      $('#room_name').val('');
      $('#is_private_room').prop('checked', false); // uncheck the checkbox 
      $('#create-room-modal').modal('toggle'); // hide the create roo modal
    });

Here’s the code for creating the room. We’re assigning the root user as the creator for all the rooms. Note that assigning a specific user as the creator of a room won’t automatically grant them permissions to do anything in the room. The only thing it implies is that they’re automatically assigned as a member of the room. So you still have to separately assign a role to them. Otherwise, the default global-scoped role will be used:

    // server/index.js
    app.post("/create-room", async (req, res) => {
      const { room_name, is_private } = req.body;
      const is_private_room = (is_private === 'true') ? true : false;

      try {
        await chatkit.createRoom({
          creatorId: 'root',
          name: room_name,
          isPrivate: is_private_room
        });

        // get the updated list of rooms
        const chatkit_rooms = await chatkit.getRooms({ includePrivate: true });
        res.send(chatkit_rooms);

      } catch (create_room_err) {
        console.log("error creating room: ", create_room_err);
      }
    });

Next, create the Handlebars template for rendering the updated list of rooms:

    <!-- server/templates/table-rooms.handlebars -->
    {{#each rooms}}
    <tr>
      <td>
        {{name}}
      </td>
      <td>
        <button type="button" class="btn btn-sm btn-warning view-users" data-id="{{id}}" data-name="{{name}}">View Users</button>
      </td>
      <td>
        <button type="button" class="btn btn-sm btn-info add-user" data-id="{{id}}" data-name="{{name}}">Add User</button>
      </td>
    </tr>
    {{/each}}

Create user

Next, add the code for making the request to the server to create a new user:

    // server/public/js/user-console.js
    $('#create-user').click(function(){
      var user_name = $('#user_name').val();
      $.post(
        "/create-user",
        {
          'user_name': user_name
        }
      );

      $('#user_name').val('');
      $('#create-user-modal').modal('toggle'); 
    });

Here’s the code for creating the user:

    // server/index.js
    app.post("/create-user", async (req, res) => {
      const { user_name } = req.body;
      const user_id = randomId(15); // generate a random user ID

      try {
        await chatkit.createUser({
          id: user_id,
          name: user_name,
          avatarURL: `https://ui-avatars.com/api/?background=d88413&color=FFF&name=${user_name}`
        });

        res.send('ok');
      } catch (create_user_err) {
        console.log("error creating user: ", create_user_err);
      }
    });

Add user to room

Next, add the code for showing the modal for adding a user to the room that was clicked:

    // server/public/js/user-console.js
    $('#rooms-table-rows').on('click', '.add-user', function() {
      var self = $(this);
      current_room_id = self.data('id');

      var room_name = self.data('name');
      setCurrentRoom(room_name);

      $('#add-user-to-room-modal').modal('toggle'); // show the modal for adding a user to the selected room
      $('#users-container').addClass('d-none'); // hide the users table

      // get list of all users from the server
      $.get(
        "/get-users",
        function(users) {
          // populate the dropdown in the modal with the list of users
          var option_users_html = Handlebars.templates\["option-users"\](users);
          $('#user_to_add').html(option_users_html);
        }
      );
    });

    function setCurrentRoom(room_name) {
      $('.current-room').html(room_name);
    }

Here’s the code for returning the list of users in this specific Chatkit app instance:

    // server/index.js
    app.get("/get-users", async (req, res) => {
      try {
        const users = await chatkit.getUsers();
        res.send({ users });
      } catch (get_users_err) {
        console.log("error getting users: ", get_users_err);
      }
    });

Here’s the template used for rendering the list of users to be used for the dropdown:

    <!-- server/templates/option-users.handlebars -->
    {{#each users}}
    <option value="{{id}}">{{name}}</option>
    {{/each}}

Next, add the code for making a request to the server to add a user to the selected room. The server returns the updated list of users in the room after the new user is added, so we also use it to refresh the users table:

    // server/public/js/user-console.js
    $('#add-user-to-room').click(function() {
      var selected_user_id = $('#user_to_add').val();

      $.post(
        "/room/add-user",
        {
          'room_id': current_room_id,
          'user_id': selected_user_id
        },
        function(room_users) {
          if (room_users.length) {
            var td_users_html = Handlebars.templates\["table-users"\]({ 'room_users': room_users });
            $('#users-table-rows').html(td_users_html);
            $('#users-container').removeClass('d-none');
          } else {
            $('#users-container').addClass('d-none'); // hide users table if no data
          }
        }
      );

      $('#add-user-to-room-modal').modal('toggle');

    });

Here’s the code for adding a user to the room. This makes three calls to the Chatkit API: adding a user to the room, getting the room, and getting users by ID. We have to make an extra method call (getUsersById) because getRoom only returns the member_user_ids. We need the user name, thus the extra method call:

    // server/index.js
    app.post("/room/add-user", async (req, res) => {
      const { room_id, user_id } = req.body;

      try {
        await chatkit.addUsersToRoom({
          roomId: room_id,
          userIds: [user_id]
        });

        const room = await chatkit.getRoom({
          roomId: room_id,
        });

        const room_users = await chatkit.getUsersById({
          userIds: room.member_user_ids,
        });

        res.send(room_users);
      } catch (add_user_to_room_err) {
        console.log("error adding user to room: ", add_user_to_room_err);
      }
    });

Here’s the template for rendering the users table:

    <!-- server/templates/table-users.handlebars -->
    {{#each room_users}}
    <tr>
      <td>
        {{name}}
      </td>
      <td>
        <button type="button" class="btn btn-sm btn-info view-roles" data-id="{{id}}" data-name="{{name}}">Set Role</button>
      </td>
    </tr>
    {{/each}}

Viewing users in a room

Next, add the code for making a request to the server to get the list of users in a specific room:

    // server/public/js/user-console.js
    $('#rooms-table-rows').on('click', '.view-users', function() {
      var self = $(this);
      var room_id = self.data('id');

      current_room_id = room_id;

      var room_name = self.data('name');
      setCurrentRoom(room_name);

      $.get(
        '/room/' + room_id + '/users',
        function(room_users) {
          if (room_users.length) {
            var td_users_html = Handlebars.templates\["table-users"\]({ 'room_users': room_users });
            $('#users-table-rows').html(td_users_html);
            $('#users-container').removeClass('d-none');
          } else {
            $('#users-container').addClass('d-none'); // hide users table if no data
          }
        }
      );
    });

Here’s the code for getting the users. This makes use of the same methods that we used earlier when we added users to the room:

    // server/index.js
    app.get("/room/:room_id/users", async (req, res) => {
      const { room_id } = req.params;

      try {
        const room = await chatkit.getRoom({
          roomId: room_id,
        });

        const room_users = await chatkit.getUsersById({
          userIds: room.member_user_ids,
        });

        res.send(room_users);
      } catch (get_room_err) {
        console.log("error getting room:", get_room_err);
      }
    });

Create role

Next, add the code for making a request to the server to create a new role. This accepts the name of the role and an array of permissions:

    // server/public/js/user-console.js
    $('#create-role').click(function() {
      var role_name = $('#role_name').val();
      var selected_permissions = [];

      // get all the checked permissions
      $.each($("input[name=permission]:checked"), function(){
        selected_permissions.push($(this).val());
      });

      $.post(
        '/create-role',
        {
          'role_name': role_name,
          'permissions': selected_permissions
        },
        function(res) {
          $('#role_name').val('');
          $('input[name=permission]').prop('checked', false); // uncheck all the permissions checkbox
        }
      );

      $('#create-role-modal').modal('toggle');
    });

Here’s the code for creating a role. Note that roles don’t have an ID, so the name you assign to it must be unique for this specific Chatkit app instance:

    // server/index.js
    app.post("/create-role", async (req, res) => {
      const { role_name, permissions } = req.body;

      try {
        await chatkit.createRoomRole({
          name: role_name,
          permissions: permissions
        });

        res.send('ok');
      } catch(create_role_err) {
        console.log("error creating role: ", create_role_err);
      }
    });

When the modal for creating a new role is shown, we uncheck all the permission checkboxes and enable them. We need to do this because we disable them when a role is being viewed (as you’ll see later):

    // server/public/js/user-console.js
    $('#create-role-modal').on('show.bs.modal', function (e) {
      $('input[name=permission]').prop({ checked: false, disabled: false });
    });

Assign role to user

Next, add the code for showing the modal for assigning a role to the selected user. In this case, the user is selected when the Set Role button next to it is clicked. Clicking that button executes this function. This makes a request to the server to get the list of roles for this specific Chatkit app instance. We then use that data to refresh the options in the Roles dropdown:

    $('#users-container').on('click', '.view-roles', function() {
      var self = $(this);
      current_user_id = self.data('id');
      current_user_name = self.data('name');

      $('.current-user').text(current_user_name);

      $('#assign-roles-modal').modal('toggle');

      $.get('/roles', function(roles) {
        instance_roles = roles;
        var option_roles_html = Handlebars.templates\["option-roles"\]({ 'roles': roles });

        $('#roles').html(option_roles_html);

        var role_name = $('#roles').val();
        showRolePermissions(role_name);
      });
    });

Here’s the template for rendering the options:

    <!-- server/templates/option-roles.handlebars -->
    {{#each roles}}
    <option value="{{name}}">{{name}}</option>
    {{/each}}

Once we get the roles data back, we also need to render the list of permissions for the currently selected role. The below function does that for us. We check all the permissions checkbox because the permissions we’re getting from the server are the permissions assigned to this role. We disable them because we don’t want the user to be updating them:

    function showRolePermissions(role_name) {
      var role_permissions = instance_roles.find(function(role) {
        return role.name === role_name;
      }).permissions;

      var role_permissions_html = Handlebars.templates\["checkbox-permissions"\]({ 'permissions': role_permissions });
      $('#role-permissions').html(role_permissions_html);

      $('input[name=permission]').prop({ 'checked': true, disabled: true });
    }

Here’s the code for returning the roles. This is an array of objects with a role_name, array of permissions, and the scope_name. The scope_name can either be global or room. The main difference between the two is that global roles don’t need to be tied to a specific room when being assigned to a user. This means that whichever room a user joins, the role will be applicable to them and they can do anything as long as they have the specific permissions. This makes global roles dangerous because they can interfere with room-scoped roles. For example, if a user has a global-scoped role which has the file:create permission enabled, but at the same time the user also has a room-scoped role which has disabled the same permission. When the user is chatting on the room where the room-scoped role is attached, they will still have the permission to attach files to a message because of the global-scoped role. One might expect the room-scoped role will take precedence, but it won’t. I created an issue on GitHub in case it’s a bug:

    // server/index.js
    app.get("/roles", async (req, res) => {
      try {
        const roles = await chatkit.getRoles();
        res.send(roles);
      } catch (get_roles_err) {
        console.log("error getting roles: ", get_roles_err);
      }
    });

When the user picks a different role from the dropdown, we render the list of permissions for that specific role:

    // server/public/js/user-console.js
    $('#roles').change(function() {
      var self = $(this);
      var role_name = self.val();

      showRolePermissions(role_name);
    });

Next, add the code for making a request to the server to assign a role to a user. This is executed when the Assign Role button in the modal for assigning a role is clicked:

    $('#assign-role-to-user').click(function() {
      var role = $('#roles').val();

      $.post(
        "/user/" + current_user_id + "/assign-role",
        {
          'room_id': current_room_id,
          'role_name': role
        }
      );

      $('#assign-roles-modal').modal('toggle');
    });

Here’s the code for assigning a role to a specific user in a room. This makes use of the assignRoomRoleToUser method. Note that assigning the same role and room combination to a user won’t duplicate the roles assigned to the user. Which is nice, because you no longer have to check if the role has already been assigned previously:

    // server/index.js
    app.post("/user/:user_id/assign-role", async (req, res) => {
      const { user_id } = req.params;
      const { room_id, role_name } = req.body;

      try {
        await chatkit.assignRoomRoleToUser({
          userId: user_id,
          name: role_name,
          roomId: room_id
        });

        res.send('ok');

      } catch (assign_role_err) {
        console.log("error assigning role to user: ", assign_role_err);
      }
    });

Lastly, expose the server on port 5000:

    const PORT = 5000;
    app.listen(PORT, (err) => {
      if (err) {
        console.error(err);
      } else {
        console.log(`Running on ports ${PORT}`);
      }
    });

Running the server

Before we can run the server, we first have to compile the client-side Handlebars templates:

    handlebars templates/option-users.handlebars -f public/templates/option-users.js
    handlebars templates/table-users.handlebars -f public/templates/table-users.js
    handlebars templates/option-roles.handlebars -f public/templates/option-roles.js
    handlebars templates/checkbox-permissions.handlebars -f public/templates/checkbox-permissions.js
    handlebars templates/table-rooms.handlebars -f public/templates/table-rooms.js

At this point, you can now run the server:

    yarn start

You can access it on your browser at http://localhost:5000/users-console.

In the next part of this series, we will be adding the roles, rooms, and users that we will be using in the React Native app.

Conclusion

In this tutorial, we learned how to create our own Node.js web app for creating rooms, creating users, and setting roles and permissions.

Stay tuned for the second part where we will build a chat app which will implement the permissions that were set in the server.

You can view the code on this GitHub repo.

Clone the project repository
  • Chat
  • JavaScript
  • Node.js
  • React Native
  • Android
  • iOS
  • Chatkit

Products

  • Channels
  • Chatkit
  • Beams

© 2019 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 160 Old Street, London, EC1V 9BW.