Adding and removing users from a business unit( Account/Org)

Adding and removing users from a business unit( Account/Org)

This is a design pattern for adding/removing users from a business unit such as an account or org. For Cashflowy, this business unit is an org. For Mr Albert, this business unit is a GSTIN(Goods and Services Tax Identification Number). For ParseMonkey, this business unit is an account. Whatever the business unit is called in each of these services, one or more users will need different kinds of access to the business unit.

User management in MrAlbert

In Mr Albert, the business unit is GSTIN. GSTIN is the unique number that Indian govt issues to a business for as a GST tax identification number. Since Mr Albert is a GST filing solution, GSTIN is the business unit in this service. More than one user can have access to a GST number. Multiple owners and employees of the business will need access to this GST. Additionally, Accountants and Auditors will also need access to this GST number.

For eg, Asyncauto(we build saas web app for clients) files GST with Indian Government. Mr Albert is a saas service that we build to simplify our own tax filing process. Mr Albert files Asyncauto’s GST every month. Here is how the user management looks like on Mr Albert.

A quick definition of various sections:

1 – GST selection dropdown. If a user has access to multiple GSTINs then, the user can switch between GSTINs using this dropdown. Since GSTIN is the primary context in this service, this option is on the navbar visible on all pages.

2 – This is where you can access settings of a particular GSTIN.

3 – Access is one of the many settings sections.

4 – This section shows all the users with access to this GSTIN

5- This is how you can the access of a user from GSTIN

6 – This section is where you can add someone to the GSTIN

Implementation details of section 5 and 6

HTML and javascript needed for add user section

<div class='ui segment'>
    <h4>Grant access to user</h4>
    <%var gstin={};%>
    <form class="ui form " action="/gstin/<%=req.gstin.value%>/settings/access/create" method='post'>
        <!-- <h4 class="ui dividing header">Shipping Information</h4> -->
        <div class="two fields">
            <div class="field">
                <label>User</label>
                <div class="ui search selection dropdown">
                    <input type="hidden"  name="user_id" >
                    <i class="dropdown icon"></i>
                    <!-- <input type="text" class="search" tabindex="0"> -->
                    <div class="default text">Search using email</div>
                    <div class="menu transition hidden" tabindex="-1">
                    </div>
                </div>
            </div>  
            <div class="field">
                <label>Access type</label>
                <div class="ui fluid selection dropdown" id='select_type' >
                <input type="hidden" name="type" value="client">
                <i class="dropdown icon"></i>
                <div class="default text">Choose type of transaction</div>
                <div class="menu">
                    <div class="item" data-value="client">Client</div>
                    <div class="item" data-value="albert_agent">Agent</div>
                    <div class="item" data-value="auditor">Auditor</div>
                </div>
            </div>
            </div>
        </div>
        
        <div class="field" style='display:none;' >
            <input type="text" name="referer"  value="<%=req.headers.referer%>">
        </div>
        <div class="ui error message">
            <div class="header">Error</div>
            <p><%=gstin.message%></p>
        </div>
        <input type="submit" class="ui basic teal button" value="Create access">
        <div class="ui success message">
            <div class="header">Creating access</div>
            Hold on tight.. we are creating access for this user. 
        </div>
    </form>
</div>
$('.search.selection.ui.dropdown').dropdown({
    apiSettings: {
        // this url parses query server side and returns filtered results
        url: '/dropdown/users?email={query}'
    },
});
$('#select_type').dropdown({});
$('.ui.form').form({
    fields: {
        user_id: 'empty',
        type : 'empty',
    },
    onSuccess:function(e,fields){
        $(this).addClass('loading');
    },
});

HTML and javascript needed for revoke user functionality

<table class="ui celled unstackable collapsing table" style="display: block;overflow-x:scroll;">
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Access</th>
            <th>Revoke</th>
        </tr>
    </thead>
    <tbody>
        <%accesses.forEach(function(a){%>
            <tr data-tid='<%=a.id%>'>
                <td class='single line'><%=a.user.name%></td>
                <td class='single line'><%=a.user.email%></td>
                <td><%=a.type%></td>
                <td class='single line'><button class="ui basic red button revoke_access" data-member-id="<%=a.id%>">Revoke</button>
            </tr>
        <%})%>
    </tbody>
</table>
$('.revoke_access').click(function(e){
    var m_id=$(this).attr('data-member-id');
    console.log('came here');
    console.log(m_id);
    var button = this;
    var c = confirm('Do you want to revoke access to this user?');
    if (c){
        $(button).addClass('loading');
        $(button).addClass('disabled');
        $.ajax({url: "/gstin/<%=req.gstin.value%>/settings/access/"+m_id+"/revoke", type: 'DELETE'},function(result,status){
            console.log(result, status)
        }).fail(function(jqXHR, textStatus, errorThrown) {
            alert("Error: "+jqXHR.responseJSON.error);
            $(button).removeClass('loading');
            $(button).removeClass('disabled');
        }).success(function() {
            window.location = "/gstin/<%=req.gstin.value%>/settings/access";
        });
    }
});

Backend api needed to support add user

dropdownListUsers:function(req,res){
    User.find({email:{contains:req.query.email}}).limit(10).exec(function(err,users){
        var data ={
            success:true,
            results:[]
        }
        users.forEach(function(user){
            var result={
                name:user.name,
                value:user.id,
                text:user.name
            }
            data.results.push(result);
        })
        res.send(data);
    });
},

Backend api needed to support revoke user

revokeAccess:function(req,res){
    Access.destroyOne({id:req.params.acc_id,gstin:req.gstin.id}).exec(function(err,result){
        if(err)
            throw err;
        
        res.send({success:'success'})
    });
},

Routes

'GET /dropdown/users':'MainController.dropdownListUsers',
'DELETE /gstin/:gst_no/settings/access/:acc_id/revoke' : 'MainController.revokeAccess',

Policies

The same policy that you apply to edit_access of the setting page will need to be applied to these controllers as well. Also, you might want to apply additional policies that define which type of user can hit the api.

Alex J V
Posted on:
Post author

Leave a comment

Your email address will not be published. Required fields are marked *